diff --git a/.github/workflows/gen-java-docs.yml b/.github/workflows/gen-java-docs.yml new file mode 100644 index 00000000..f15e03cc --- /dev/null +++ b/.github/workflows/gen-java-docs.yml @@ -0,0 +1,35 @@ +name: Generate Java Docs + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up JDK 11 + uses: actions/setup-java@v4 + with: + java-version: 11 + distribution: corretto + + - name: Build with Maven + run: mvn clean install + + - name: Generate Javadocs + run: mvn javadoc:javadoc + + # Publishes Javadocs to GitHub Pages by pushing to `gh-pages` branch + - name: Deploy Javadocs to GitHub Pages + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + mvn scm-publish:publish-scm + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7544666b..1439ea00 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,25 +20,24 @@ jobs: java-version: 11 distribution: corretto cache: maven - server-id: ossrh # Value of distributionManagement.repository.id field of pom.xml + server-id: central # Value of distributionManagement.repository.id field of pom.xml server-username: MAVEN_USERNAME server-password: MAVEN_PASSWORD settings-path: ${{ github.workspace }} # Location for settings.xml file - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY_ABHI }} gpg-passphrase: GPG_PASSPHRASE - name: Publish with Maven deploy - run: > - mvn - --batch-mode - --activate-profiles deploy - --settings $GITHUB_WORKSPACE/settings.xml - -Pcoverage - clean deploy + run: | + if [ "${{ env.ACTIONS_STEP_DEBUG }}" == "true" ]; then + mvn --batch-mode --activate-profiles deploy --settings $GITHUB_WORKSPACE/settings.xml -Pcoverage clean deploy -X + else + mvn --batch-mode --activate-profiles deploy --settings $GITHUB_WORKSPACE/settings.xml -Pcoverage clean deploy + fi env: MAVEN_USERNAME: ${{ secrets.NEXUS_USERNAME }} MAVEN_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} - GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE_ABHI }} - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 diff --git a/.gitignore b/.gitignore index f9a2b3a8..dd496563 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ target .idea *.iml +## VS Code +.vscode + ## Logs *.log @@ -27,3 +30,6 @@ dependency-reduced-pom.xml # mvn release pom.xml.releaseBackup release.properties + +# macOS +.DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a49889b..af4ce57a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ alternative to the GitHub API. ## Getting Started -The Github Java Clients's [open issues are here](https://github.com/github-java-client/github-java-client/issues). +The Github Java Clients's [open issues are here](https://github.com/spotify/github-java-client/issues). In time, we'll tag issues that would make a good first pull request for new contributors. An easy way to get started helping the project is to *file an issue*. Issues can include bugs to fix, features to add, or documentation that looks outdated. @@ -39,4 +39,4 @@ feedback for changes that would be required. [/orgs/{org}/teams/{team_slug}](https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#list-teams) endpoint - We operate a monkey see, monkey do approach to this library. We understand that there are some inconsistencies in the library in terms of how the tests and/or endpoints are written but we, with your help, are working on creating a more consistent codebase. -- All bug fixes and new features need to be fully tested. \ No newline at end of file +- All bug fixes and new features need to be fully tested. diff --git a/README.md b/README.md index 73f55abb..a87acd16 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ +# WE ARE NO LONGER ACCEPTING CHANGES TO THIS REPOSITORY AND WILL BE DISCONTINUING SUPPORT FOR THIS PROJECT END OF JAN 2026 +Please see alternatives such as a https://github.com/hub4j/github-api + ![release pipeline](https://github.com/spotify/github-java-client/actions/workflows/release.yml/badge.svg) [![codecov](https://codecov.io/gh/spotify/github-java-client/branch/master/graph/badge.svg?token=ADHNCIESSL)](https://codecov.io/gh/spotify/github-java-client)[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) ![lifecycle: beta](https://img.shields.io/badge/lifecycle-beta-509bf5.svg) [![Maven Central](https://img.shields.io/maven-central/v/com.spotify/github-client)](https://mvnrepository.com/artifact/com.spotify/github-client) - # github-java-client A small Java library for talking to GitHub/GitHub Enterprise and interacting with projects. @@ -22,11 +24,13 @@ You can find this library in [maven central repository](https://mvnrepository.co Include the latest version of github-client into your project: In Maven: + ```xml + - com.spotify - github-client - version + com.spotify + github-client + version ``` @@ -44,10 +48,10 @@ To authenticate as a GitHub App, you must provide a private key and the App ID, ```java final GitHubClient githubClient = - GitHubClient.create( - URI.create("https://api.github.com/"), - new File("/path-to-the/private-key.pem"), - APP_ID); + GitHubClient.create( + URI.create("https://api.github.com/"), + new File("/path-to-the/private-key.pem"), + APP_ID); ``` Then, you can scope the client for a specific Installation ID, to do the operations at the installation level. @@ -60,12 +64,16 @@ final GitHubClient scopedClient = GitHubClient.scopeForInstallationId(githubClie It is also possible to provide the installation to the root client. -Refer to [GitHub App Authentication Guide](https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/) for more information. +Refer +to [GitHub App Authentication Guide](https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/) +for more information. ## Usage -This library attempts to mirror the structure of GitHub API endpoints. As an example, to get details of a Commit, there is -the `GET /repos/:owner/:repo/commits` API call, under the `repos` API. Therefore, the `getCommit` method lives in the RepositoryClient. +This library attempts to mirror the structure of GitHub API endpoints. As an example, to get details of a Commit, there +is +the `GET /repos/:owner/:repo/commits` API call, under the `repos` API. Therefore, the `getCommit` method lives in the +RepositoryClient. ```java final RepositoryClient repositoryClient = githubClient.createRepositoryClient("my-org", "my-repo"); @@ -74,20 +82,62 @@ log.info(repositoryClient.getCommit("sha").get().htmlUrl()); Another example of the mirrored structure is that some of the APIs are nested under a parent API. For example, endpoints related to check runs or issues are nested under the Repository client: + ```java final ChecksClient checksClient = repositoryClient.createChecksApiClient(); checksClient.createCheckRun(CHECK_RUN_REQUEST); final IssueClient issueClient = repositoryClient.createIssueClient(); -issueClient.createComment(ISSUE_ID, "comment body") - .thenAccept(comment -> log.info("created comment " + comment.htmlUrl())); +issueClient + .createComment(ISSUE_ID, "comment body") + .thenAccept(comment ->log.info("created comment "+comment.htmlUrl())); ``` And endpoints related to teams and memberships are nested under the Organisation client: + ```java final TeamClient teamClient = organisationClient.createTeamClient(); - teamClient.getMembership("username"); +teamClient.getMembership("username"); +``` + +## Tracing + +The GitHub client supports tracing via both OpenCensus and OpenTelemetry. Since OpenCensus is deprecated, we recommend +using OpenTelemetry. Using OpenTelemetry also enables context propagation when using this library. +To enable tracing, you need to provide a tracer when initializing the client. + +### OpenTelemetry + +```java +import com.spotify.github.tracing.opentelemetry.OpenTelemetryTracer; + +final GitHubClient githubClient = + GitHubClient.create(baseUri, accessToken) + // Uses GlobalOpenTelemetry.get() to fetch the default tracer + .withTracer(new OpenTelemetryTracer()); +``` + +You can also provide a custom `OpenTelemetry` object if you want to use a specific one. + +```java +import com.spotify.github.tracing.opentelemetry.OpenTelemetryTracer; + +final GitHubClient githubClient = + GitHubClient.create(baseUri, accessToken) + // Uses custom openTelemetry object to fetch the tracer + .withTracer(new OpenTelemetryTracer(openTelemetry)); +``` + +### OpenCensus + +```java +import com.spotify.github.tracing.opencensus.OpenCensusTracer; + +final GitHubClient githubClient = + GitHubClient.create(baseUri, accessToken) + // Uses Tracing.getTracer() to fetch the default tracer + .withTracer(new OpenCensusTracer()); ``` ## Supported Java versions @@ -104,9 +154,14 @@ This project uses Maven. To run the tests locally, just run: mvn clean verify ``` -If you are a maintainer, you can release a new version by just triggering the workflow -[prepare-release](./.github/workflows/prepare-release.yml) through the +### Maintainers + +#### Publishing a new version + +If you are a maintainer, you can release a new version by just triggering the workflow +[prepare-release](./.github/workflows/prepare-release.yml) through the [web UI](https://github.com/spotify/github-java-client/actions/workflows/prepare-release.yml). + - Select whether the new release should be a `major`, `minor` or `patch` release - Trigger the release preparation on the `master` branch - Pushes of this workflow will trigger runs of the @@ -115,15 +170,56 @@ If you are a maintainer, you can release a new version by just triggering the wo [github-release](https://github.com/spotify/github-java-client/actions/workflows/release-on-github.yml) workflow with the automatically created tag +The `prepare-release` workflow will also update the snapshot version in the `pom.xml` file to the next version. The +version which will be published to Maven Central will be the one specified in the `pom.xml` file (without the +`-SNAPSHOT` suffix). + +#### Updating the GPG signing key + +If you need to update the GPG signing key used for signing the releases when the existing key expires, you can do so by +following these steps: + +1. Generate a new GPG key pair or use an existing one. + If you don't have a GPG key pair, you can generate one using the following command: + ```bash + gpg --full-generate-key + ``` + Follow the prompts to create your key pair. Make sure to remember the passphrase you set. +2. List your GPG keys to find the key ID: + ```bash + gpg --list-keys + ``` + Look for the `pub` line, which will show the key ID in the format `XXXXXXXX`. +3. Export the public key to a file: + ```bash + gpg --armor --export > publickey.asc + ``` +4. export the private key to a file: + ```bash + gpg --armor --export-secret-key > privatekey.asc + ``` +5. Upload the private key to the GitHub repository secrets in `GPG_PRIVATE_KEY` and paste the contents of + `privatekey.asc`. +6. Update the passphrase in the `GPG_PASSPHRASE` secret with the passphrase you set when generating the key. +7. Upload the public key to the OpenGpg key server at https://keys.openpgp.org/ +8. Make sure to verify the public key with your email address on OpenGPG and that it is available on the key server. +9. Make sure that the release workflow is configured to use the `GPG_PRIVATE_KEY` and `GPG_PASSPHRASE` secrets. +10. Run the release workflow to publish a new version of the library. + ## Notes about maturity This module was created after existing libraries were evaluated and dismissed, and we found that we were writing similar -code in multiple projects. As such, it at least initially only contains enough functionality for our internal requirements -which reflects that we were working on build system integration with the GitHub pull requests. It has been widely used for 4+ -years. It's important to notice that it does not cover all GitHub v3 API. Adding missing endpoints should be very straightforward. +code in multiple projects. As such, it at least initially only contains enough functionality for our internal +requirements +which reflects that we were working on build system integration with the GitHub pull requests. It has been widely used +for 4+ +years. It's important to notice that it does not cover all GitHub v3 API. Adding missing endpoints should be very +straightforward. Pull Requests are welcome. ## Code of conduct -This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to honor this code. + +This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to honor this +code. [code-of-conduct]: https://github.com/spotify/code-of-conduct/blob/master/code-of-conduct.md diff --git a/pom.xml b/pom.xml index 600a61fd..fc13b6e7 100644 --- a/pom.xml +++ b/pom.xml @@ -1,9 +1,9 @@ 4.0.0 - + github-java-client github-client - 0.2.20-SNAPSHOT + 0.5.6-SNAPSHOT com.spotify @@ -23,42 +23,25 @@ scm:git:https://github.com/spotify/github-java-client.git scm:git:git@github.com:spotify/github-java-client.git scm:https://github.com/spotify/github-java-client/ - HEAD + v0.3.7 Spotify AB - http://www.spotify.com + https://www.spotify.com - ossrh - https://oss.sonatype.org/content/repositories/snapshots + central + https://central.sonatype.com/repository/maven-snapshots/ - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + central + https://central.sonatype.com/repository/maven-releases/ - - - henriquetruta - Henrique Truta - henriquet@spotify.com - Spotify AB - http://www.spotify.com - - - hewhomustnotbenamed - Abhimanyu Shegokar - abhimanyus@spotify.com - Spotify AB - http://www.spotify.com - - - apache.snapshots @@ -84,7 +67,7 @@ UTF-8 UTF-8 - 1718369863 + 1765470064 spotbugsexclude.xml error checkstyle.xml @@ -97,13 +80,12 @@ 1.7.36 5.6.0 2.6 - 2.15.3 + 2.20.1 2.9.3 3.3 0.31.1 4.11.0 - - ${project.groupId}.githubclient.shade + 1.51.0 @@ -120,6 +102,13 @@ import pom + + io.opentelemetry + opentelemetry-bom + ${opentelemetry.version} + pom + import + @@ -149,6 +138,11 @@ jsr311-api ${jsr311-api.version} + + org.apache.httpcomponents + httpclient + 4.5.14 + com.fasterxml.jackson.core jackson-annotations @@ -179,6 +173,30 @@ opencensus-api ${opencensus.version} + + + io.opentelemetry + opentelemetry-api + + + io.opentelemetry + opentelemetry-sdk + + + io.opentelemetry + opentelemetry-sdk-testing + + + io.opentelemetry.instrumentation + opentelemetry-okhttp-3.0 + 2.8.0-alpha + + + commons-io + commons-io + 2.14.0 + compile + io.jsonwebtoken jjwt-impl @@ -209,6 +227,12 @@ 2.2 test + + com.github.npathai + hamcrest-optional + 2.0.0 + test + org.junit.jupiter junit-jupiter-engine @@ -221,6 +245,12 @@ ${junit.version} test + + org.junit.jupiter + junit-jupiter-params + ${junit.version} + test + org.mockito @@ -249,67 +279,67 @@ commons-io commons-io - 2.7 + 2.14.0 compile - coverage - - - - org.jacoco - jacoco-maven-plugin - 0.8.5 - - - - - **/*Builder* - **/*Immutable* - **/*_Factory* - **/*_*Factory*.* - **/generated-sources*.* - - - - BUNDLE - - - INSTRUCTION - COVEREDRATIO - 0.60 - - - - - - - - pre-test - - prepare-agent - - - - default-check - - check - - - - post-unit-test - test - - report - - - - - - + coverage + + + + org.jacoco + jacoco-maven-plugin + 0.8.5 + + + + + **/*Builder* + **/*Immutable* + **/*_Factory* + **/*_*Factory*.* + **/generated-sources*.* + + + + BUNDLE + + + INSTRUCTION + COVEREDRATIO + 0.60 + + + + + + + + pre-test + + prepare-agent + + + + default-check + + check + + + + post-unit-test + test + + report + + + + + + @@ -329,9 +359,11 @@ sign + --pinentry-mode loopback + --no-tty @@ -351,25 +383,35 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.13 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 true - ossrh - https://oss.sonatype.org/ - true + central + github-java-client + true + published - + maven-compiler-plugin + + + default-compile + generate-sources + + compile + + + 11 11 @@ -415,7 +457,7 @@ maven-enforcer-plugin - 1.4.1 + 3.6.2 enforce @@ -451,41 +493,10 @@ - - org.apache.maven.plugins - maven-shade-plugin - 3.2.3 - - - package - - shade - - - - - ${project.groupId}:${project.artifactId} - com.squareup.okhttp3 - com.squareup.okio - - - - - okhttp3 - ${shade.id}.okhttp3 - - - okio - ${shade.id}.okio - - - - - - org.apache.maven.plugins maven-javadoc-plugin + 3.3.1 attach-javadocs @@ -499,6 +510,16 @@ none + + org.apache.maven.plugins + maven-scm-publish-plugin + 1.0 + + target/site/apidocs + scm:git:git@github.com:spotify/github-java-client.git + gh-pages + + diff --git a/src/main/java/com/spotify/github/async/Async.java b/src/main/java/com/spotify/github/async/Async.java index b35ef7bb..cb49608b 100644 --- a/src/main/java/com/spotify/github/async/Async.java +++ b/src/main/java/com/spotify/github/async/Async.java @@ -20,6 +20,8 @@ package com.spotify.github.async; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; import java.util.stream.Stream; import static java.util.stream.StreamSupport.stream; @@ -34,4 +36,19 @@ public static Stream streamFromPaginatingIterable(final Iterable stream(page.spliterator(), false)); } + + public static CompletableFuture exceptionallyCompose( + final CompletableFuture future, final Function> handler) { + + return future + .handle( + (result, throwable) -> { + if (throwable != null) { + return handler.apply(throwable); + } else { + return CompletableFuture.completedFuture(result); + } + }) + .thenCompose(Function.identity()); + } } diff --git a/src/main/java/com/spotify/github/http/BaseHttpResponse.java b/src/main/java/com/spotify/github/http/BaseHttpResponse.java new file mode 100644 index 00000000..0731e041 --- /dev/null +++ b/src/main/java/com/spotify/github/http/BaseHttpResponse.java @@ -0,0 +1,129 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.http; + +import java.util.List; +import java.util.Map; + +/** BaseHttpResponse is the base implementation of HttpResponse. */ +public abstract class BaseHttpResponse implements HttpResponse { + private static final int HTTP_OK = 200; + private static final int HTTP_BAD_REQUEST = 400; + + protected final HttpRequest request; + protected final int statusCode; + protected final String statusMessage; + protected final Map> headers; + + public BaseHttpResponse( + final HttpRequest request, + final int statusCode, + final String statusMessage, + final Map> headers) { + this.request = request; + this.statusCode = statusCode; + this.statusMessage = statusMessage; + this.headers = headers; + } + + /** + * Returns the request that generated this response. + * + * @return HttpRequest the request that generated this response + */ + @Override + public HttpRequest request() { + return request; + } + + /** + * Returns the HTTP status code of the response. + * + * @return the status code of the response + */ + @Override + public int statusCode() { + return statusCode; + } + + /** + * Returns the HTTP status message of the response. + * + * @return the status message of the response + */ + @Override + public String statusMessage() { + return statusMessage; + } + + /** + * Returns the headers of the response. + * + * @return the headers of the response as a Map of strings + */ + @Override + public Map> headers() { + return this.headers; + } + + /** + * Returns the values of the header with the given name. If the header is not present, this method + * returns null. + * + * @param headerName the name of the header + * @return the values of the header with the given name as a List of strings, or null if the + * header is not present + */ + @Override + public List headers(final String headerName) { + return this.headers.get(headerName); + } + + /** + * Returns the first value of the header with the given name. If the header is not present, this + * method returns null. + * + * @param headerName the name of the header + * @return the first value of the header with the given name, or null if the header is not present + */ + @Override + public String header(final String headerName) { + List headerValues = this.headers(headerName); + if (headerValues == null || headerValues.isEmpty()) { + return null; + } + if (headerValues.size() == 1) { + return headerValues.get(0); + } else { + return String.join(",", headerValues); + } + } + + /** + * Was the request successful? + * + * @return true if the status code is in the range [200, 400) + */ + @Override + public boolean isSuccessful() { + return this.statusCode() >= HTTP_OK && this.statusCode() < HTTP_BAD_REQUEST; + } +} diff --git a/src/main/java/com/spotify/github/Span.java b/src/main/java/com/spotify/github/http/HttpClient.java similarity index 71% rename from src/main/java/com/spotify/github/Span.java rename to src/main/java/com/spotify/github/http/HttpClient.java index 70b2e939..bc29e158 100644 --- a/src/main/java/com/spotify/github/Span.java +++ b/src/main/java/com/spotify/github/http/HttpClient.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,16 +18,12 @@ * -/-/- */ -package com.spotify.github; +package com.spotify.github.http; -public interface Span extends AutoCloseable { +import com.spotify.github.tracing.Tracer; +import java.util.concurrent.CompletableFuture; - Span success(); - - Span failure(Throwable t); - - /** Close span. Must be called for any opened span. */ - @Override - void close(); +public interface HttpClient { + CompletableFuture send(HttpRequest request); + void setTracer(Tracer tracer); } - diff --git a/src/main/java/com/spotify/github/http/HttpRequest.java b/src/main/java/com/spotify/github/http/HttpRequest.java new file mode 100644 index 00000000..018797ca --- /dev/null +++ b/src/main/java/com/spotify/github/http/HttpRequest.java @@ -0,0 +1,67 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.http; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.GithubStyle; +import java.util.List; +import java.util.Map; +import org.immutables.value.Value; + +import javax.annotation.Nullable; + +@Value.Immutable +@GithubStyle +@JsonSerialize(as = ImmutableHttpRequest.class) +@JsonDeserialize(as = ImmutableHttpRequest.class) +public interface HttpRequest { + @Value.Default + default String method() { + return "GET"; + } + + String url(); + + @Nullable + String body(); + + @Value.Default + default Map> headers() { + return Map.of(); + } + + default List headers(String headerName) { + return headers().get(headerName); + } + + default String header(String headerName) { + List headerValues = this.headers(headerName); + if (headerValues == null || headerValues.isEmpty()) { + return null; + } + if (headerValues.size() == 1) { + return headerValues.get(0); + } else { + return String.join(",", headerValues); + } + } +} diff --git a/src/main/java/com/spotify/github/http/HttpResponse.java b/src/main/java/com/spotify/github/http/HttpResponse.java new file mode 100644 index 00000000..34b9488c --- /dev/null +++ b/src/main/java/com/spotify/github/http/HttpResponse.java @@ -0,0 +1,48 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.http; + +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +public interface HttpResponse { + // Returns the request that was sent to the server + HttpRequest request(); + // Returns the HTTP status code + int statusCode(); + // Returns the HTTP status message + String statusMessage(); + // Returns the response body as an InputStream + InputStream body(); + // Returns the response body as a String + String bodyString(); + // Returns the response headers as a Map + Map> headers(); + // Returns the response headers for a specific header name as a list of Strings + List headers(String headerName); + // Returns the response headers for a specific header name as a single String + String header(String headerName); + // Returns true if the response was successful + boolean isSuccessful(); + // Closes the response + void close(); +} diff --git a/src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java b/src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java new file mode 100644 index 00000000..c5ef9bc4 --- /dev/null +++ b/src/main/java/com/spotify/github/http/okhttp/OkHttpHttpClient.java @@ -0,0 +1,242 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.http.okhttp; + +import static okhttp3.MediaType.parse; + +import com.google.common.annotations.VisibleForTesting; +import com.spotify.github.http.HttpClient; +import com.spotify.github.http.HttpRequest; +import com.spotify.github.http.HttpResponse; +import com.spotify.github.http.ImmutableHttpRequest; +import com.spotify.github.tracing.NoopTracer; +import com.spotify.github.tracing.Span; +import com.spotify.github.tracing.TraceHelper; +import com.spotify.github.tracing.Tracer; +import com.spotify.github.tracing.opencensus.OpenCensusTracer; +import com.spotify.github.tracing.opentelemetry.OpenTelemetryTracer; +import io.opentelemetry.instrumentation.okhttp.v3_0.OkHttpTelemetry; +import java.io.IOException; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; + +/** + * OkHttpHttpClient is the implementation of HttpClient using OkHttp. This also serves as an example + * of how to create a custom HttpClient. This HttpClient is also capable of tracing the requests + * using OpenCensus or OpenTelemetry. + */ +public class OkHttpHttpClient implements HttpClient { + private final OkHttpClient client; + private Tracer tracer; + private Call.Factory callFactory; + + public OkHttpHttpClient(final OkHttpClient client) { + this.client = client; + this.tracer = NoopTracer.INSTANCE; + this.callFactory = createTracedClient(); + } + + public OkHttpHttpClient(final OkHttpClient client, final Tracer tracer) { + this.client = client; + this.tracer = tracer; + this.callFactory = createTracedClient(); + } + + /** + * Send a request and return a future with the response. + * + * @param httpRequest the request to send + * @return a future with the response + */ + @Override + public CompletableFuture send(final HttpRequest httpRequest) { + Request request = buildOkHttpRequest(httpRequest); + CompletableFuture future = new CompletableFuture<>(); + try (Span span = tracer.span(httpRequest)) { + if (this.callFactory == null) { + this.callFactory = createTracedClient(); + } + tracer.attachSpanToFuture(span, future); + try { + this.callFactory + .newCall(request) + .enqueue( + new Callback() { + + @Override + public void onResponse(@NotNull final Call call, @NotNull final Response response) + throws IOException { + future.complete(new OkHttpHttpResponse(httpRequest, response)); + } + + @Override + public void onFailure(@NotNull final Call call, @NotNull final IOException e) { + future.completeExceptionally(e); + } + }); + } catch (Exception e) { + future.completeExceptionally(e); + } + } + return future; + } + + @Override + public void setTracer(final Tracer tracer) { + this.tracer = tracer; + this.callFactory = createTracedClient(); + } + + /** + * Build an OkHttp Request from an HttpRequest. + * + * @param request the HttpRequest + * @return the OkHttp Request + */ + private Request buildOkHttpRequest(final HttpRequest request) { + Request.Builder requestBuilder = new Request.Builder().url(request.url()); + request + .headers() + .forEach( + (key, values) -> { + values.forEach(value -> requestBuilder.addHeader(key, value)); + }); + if (request.method().equals("GET")) { + requestBuilder.get(); + } else { + requestBuilder.method( + request.method(), + RequestBody.create(parse(javax.ws.rs.core.MediaType.APPLICATION_JSON), request.body())); + } + return requestBuilder.build(); + } + + /** + * Build an HttpRequest from an OkHttp Request. + * + * @param request the OkHttp Request + * @return the HttpRequest + */ + private HttpRequest buildHttpRequest(final Request request) { + return ImmutableHttpRequest.builder() + .url(request.url().toString()) + .method(request.method()) + .headers(request.headers().toMultimap()) + .body(Optional.ofNullable(request.body()).map(RequestBody::toString).orElse("")) + .build(); + } + + /** + * Create a traced client based on the tracer. + * + * @return the traced client + */ + private Call.Factory createTracedClient() { + if (this.tracer == null || this.tracer instanceof NoopTracer) { + return createTracedClientNoopTracer(); + } + if (this.tracer instanceof OpenCensusTracer) { + return createTracedClientOpenCensus(); + } + if (this.tracer instanceof OpenTelemetryTracer) { + return createTracedClientOpenTelemetry(); + } + return createTracedClientNoopTracer(); + } + + /** + * Create a traced client with a NoopTracer. + * + * @return the traced client + */ + protected Call.Factory createTracedClientNoopTracer() { + return new Call.Factory() { + @NotNull + @Override + public Call newCall(@NotNull final Request request) { + return client.newCall(request); + } + }; + } + + /** + * Create a traced client with OpenTelemetry. + * + * @return the traced client + */ + @VisibleForTesting + protected Call.Factory createTracedClientOpenTelemetry() { + // OkHttpTelemetry is a helper class that provides a Call.Factory that can be used to trace + return OkHttpTelemetry.builder(((OpenTelemetryTracer) this.tracer).getOpenTelemetry()) + .build() + .newCallFactory(client); + } + + /** + * Create a traced client with OpenCensus. + * + * @return the traced client + */ + protected Call.Factory createTracedClientOpenCensus() { + return new Call.Factory() { + @NotNull + @Override + public Call newCall(@NotNull final Request request) { + CompletableFuture future = new CompletableFuture<>(); + Span span = + OkHttpHttpClient.this + .tracer + .span(buildHttpRequest(request)) + .addTag(TraceHelper.TraceTags.HTTP_URL, request.url().toString()); + OkHttpClient.Builder okBuilder = client.newBuilder(); + // Add a network interceptor to trace the request + okBuilder + .networkInterceptors() + .add( + 0, + new Interceptor() { + @NotNull + @Override + public Response intercept(@NotNull final Chain chain) throws IOException { + try { + Response response = chain.proceed(chain.request()); + span.addTag(TraceHelper.TraceTags.HTTP_STATUS_CODE, response.code()) + .addTag(TraceHelper.TraceTags.HTTP_STATUS_MESSAGE, response.message()) + .success(); + future.complete(response); + return response; + } catch (Exception ex) { + span.failure(ex); + future.completeExceptionally(ex); + throw ex; + } finally { + span.close(); + } + } + }); + + return okBuilder.build().newCall(request); + } + }; + } +} diff --git a/src/main/java/com/spotify/github/http/okhttp/OkHttpHttpResponse.java b/src/main/java/com/spotify/github/http/okhttp/OkHttpHttpResponse.java new file mode 100644 index 00000000..b668ab31 --- /dev/null +++ b/src/main/java/com/spotify/github/http/okhttp/OkHttpHttpResponse.java @@ -0,0 +1,96 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.http.okhttp; + +import com.spotify.github.http.BaseHttpResponse; +import com.spotify.github.http.HttpRequest; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.invoke.MethodHandles; +import java.util.Optional; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** OkHttpHttpResponse is the implementation of HttpResponse using OkHttp. */ +public class OkHttpHttpResponse extends BaseHttpResponse { + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + private final Response response; + private InputStream body; + private String bodyString; + + public OkHttpHttpResponse(final HttpRequest request, final Response response) { + super(request, response.code(), response.message(), response.headers().toMultimap()); + this.response = response; + } + + @Override + public InputStream body() { + if (body == null) { + body = Optional.ofNullable(response.body()).map(ResponseBody::byteStream).orElse(null); + } + return body; + } + + @Override + public String bodyString() { + if (bodyString == null) { + if (response != null) { + bodyString = responseBodyUnchecked(response); + } + } + return bodyString; + } + + @Override + public void close() { + try { + if (response != null) { + if (response.body() != null) { + response.body().close(); + } + response.close(); + } + } catch (IllegalStateException e) { + log.debug("Failed closing response: {}", e.getMessage()); + } + } + + /** + * Get the response body as a string. + * + * @param response the response + * @return the response body as a string + */ + private static String responseBodyUnchecked(final Response response) { + if (response.body() == null) { + return null; + } + try (ResponseBody body = response.body()) { + return body.string(); + } catch (IOException e) { + throw new UncheckedIOException("Failed getting response body for: " + response, e); + } + } +} diff --git a/src/main/java/com/spotify/github/jackson/CommentReactionContentDeserializer.java b/src/main/java/com/spotify/github/jackson/CommentReactionContentDeserializer.java new file mode 100644 index 00000000..abbaeb73 --- /dev/null +++ b/src/main/java/com/spotify/github/jackson/CommentReactionContentDeserializer.java @@ -0,0 +1,43 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ +package com.spotify.github.jackson; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.spotify.github.v3.comment.CommentReactionContent; + +import java.io.IOException; +/** + * Custom deserializer for {@link CommentReactionContent}. + */ +public class CommentReactionContentDeserializer extends JsonDeserializer { + @Override + public CommentReactionContent deserialize(final JsonParser p, final DeserializationContext ctxt) + throws IOException { + String value = p.getText(); + for (CommentReactionContent content : CommentReactionContent.values()) { + if (content.toString().equals(value)) { + return content; + } + } + return null; + } +} diff --git a/src/main/java/com/spotify/github/jackson/CommentReactionContentSerializer.java b/src/main/java/com/spotify/github/jackson/CommentReactionContentSerializer.java new file mode 100644 index 00000000..c476dc49 --- /dev/null +++ b/src/main/java/com/spotify/github/jackson/CommentReactionContentSerializer.java @@ -0,0 +1,35 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ +package com.spotify.github.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.spotify.github.v3.comment.CommentReactionContent; +import java.io.IOException; +/** + * Custom serializer for {@link CommentReactionContent}. + */ +public class CommentReactionContentSerializer extends JsonSerializer { + @Override + public void serialize(final CommentReactionContent value, final JsonGenerator gen, final SerializerProvider serializers) throws IOException { + gen.writeString(value.toString()); + } +} diff --git a/src/main/java/com/spotify/github/jackson/Json.java b/src/main/java/com/spotify/github/jackson/Json.java index c77c06f3..31435b7c 100644 --- a/src/main/java/com/spotify/github/jackson/Json.java +++ b/src/main/java/com/spotify/github/jackson/Json.java @@ -20,7 +20,7 @@ package com.spotify.github.jackson; -import static com.fasterxml.jackson.databind.PropertyNamingStrategy.SNAKE_CASE; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; import static java.util.Objects.isNull; import com.fasterxml.jackson.annotation.JsonInclude; @@ -248,6 +248,6 @@ private static class DefaultMapper { .enable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID) .enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES) .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .setPropertyNamingStrategy(SNAKE_CASE); + .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); } } diff --git a/src/main/java/com/spotify/github/opencensus/OpenCensusSpan.java b/src/main/java/com/spotify/github/opencensus/OpenCensusSpan.java index 1bbf15ec..e513a58e 100644 --- a/src/main/java/com/spotify/github/opencensus/OpenCensusSpan.java +++ b/src/main/java/com/spotify/github/opencensus/OpenCensusSpan.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,45 +19,20 @@ */ package com.spotify.github.opencensus; -import static java.util.Objects.requireNonNull; -import com.spotify.github.Span; -import com.spotify.github.v3.exceptions.RequestNotOkException; -import io.opencensus.trace.AttributeValue; -import io.opencensus.trace.Status; -class OpenCensusSpan implements Span { +import io.opencensus.trace.Span; - public static final int NOT_FOUND = 404; - public static final int INTERNAL_SERVER_ERROR = 500; - private final io.opencensus.trace.Span span; - - OpenCensusSpan(final io.opencensus.trace.Span span) { - this.span = requireNonNull(span); - } - - @Override - public Span success() { - span.setStatus(Status.OK); - return this; - } - - @Override - public Span failure(final Throwable t) { - if (t instanceof RequestNotOkException) { - RequestNotOkException ex = (RequestNotOkException) t; - span.putAttribute("http.status_code", AttributeValue.longAttributeValue(ex.statusCode())); - span.putAttribute("message", AttributeValue.stringAttributeValue(ex.getRawMessage())); - if (ex.statusCode() - INTERNAL_SERVER_ERROR >= 0) { - span.putAttribute("error", AttributeValue.booleanAttributeValue(true)); - } - } - span.setStatus(Status.UNKNOWN); - return this; - } - - @Override - public void close() { - span.end(); - } +/** + * OpenCensusSpan is a wrapper around OpenCensus Span. This class is kept for backward + * compatibility. + * + * @deprecated This class has been moved to the package com.spotify.github.tracing.opencensus. + * Please use com.spotify.github.tracing.opencensus.OpenCensusSpan instead. + */ +@Deprecated +public class OpenCensusSpan extends com.spotify.github.tracing.opencensus.OpenCensusSpan { + public OpenCensusSpan(final Span span) { + super(span); + } + // This class is kept for backward compatibility } - diff --git a/src/main/java/com/spotify/github/opencensus/OpenCensusTracer.java b/src/main/java/com/spotify/github/opencensus/OpenCensusTracer.java index d4834b34..6f1b00c5 100644 --- a/src/main/java/com/spotify/github/opencensus/OpenCensusTracer.java +++ b/src/main/java/com/spotify/github/opencensus/OpenCensusTracer.java @@ -2,14 +2,14 @@ * -\-\- * github-api * -- - * Copyright (C) 2021 Spotify AB + * Copyright (C) 2016 - 2021 Spotify AB * -- * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,52 +20,14 @@ package com.spotify.github.opencensus; -import com.spotify.github.Span; -import com.spotify.github.Tracer; -import io.opencensus.trace.Tracing; - -import java.util.concurrent.CompletionStage; - -import static io.opencensus.trace.AttributeValue.stringAttributeValue; -import static io.opencensus.trace.Span.Kind.CLIENT; -import static java.util.Objects.requireNonNull; - -public class OpenCensusTracer implements Tracer { - - private static final io.opencensus.trace.Tracer TRACER = Tracing.getTracer(); - - @Override - public Span span(final String name, final String method, final CompletionStage future) { - return internalSpan(name, method, future); - } - - @SuppressWarnings("MustBeClosedChecker") - private Span internalSpan( - final String path, - final String method, - final CompletionStage future) { - requireNonNull(path); - requireNonNull(future); - - final io.opencensus.trace.Span ocSpan = - TRACER.spanBuilder("GitHub Request").setSpanKind(CLIENT).startSpan(); - - ocSpan.putAttribute("component", stringAttributeValue("github-api-client")); - ocSpan.putAttribute("peer.service", stringAttributeValue("github")); - ocSpan.putAttribute("http.url", stringAttributeValue(path)); - ocSpan.putAttribute("method", stringAttributeValue(method)); - final Span span = new OpenCensusSpan(ocSpan); - - future.whenComplete( - (result, t) -> { - if (t == null) { - span.success(); - } else { - span.failure(t); - } - span.close(); - }); - - return span; - } +/** + * OpenCensusTracer is a wrapper around OpenCensus Tracer. This class is kept for backward + * compatibility. + * + * @deprecated This class has been moved to the package com.spotify.github.tracing.opencensus. + * Please use com.spotify.github.tracing.opencensus.OpenCensusTracer instead. + */ +@Deprecated +public class OpenCensusTracer extends com.spotify.github.tracing.opencensus.OpenCensusTracer { + // This class is kept for backward compatibility } diff --git a/src/main/java/com/spotify/github/tracing/BaseTracer.java b/src/main/java/com/spotify/github/tracing/BaseTracer.java new file mode 100644 index 00000000..f0ed42a0 --- /dev/null +++ b/src/main/java/com/spotify/github/tracing/BaseTracer.java @@ -0,0 +1,73 @@ +/*- + * -\-\- + * github-client + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.tracing; + +import static java.util.Objects.requireNonNull; + +import com.spotify.github.http.HttpRequest; +import java.util.concurrent.CompletionStage; + +public abstract class BaseTracer implements Tracer { + @Override + public Span span(final String name, final String method, final CompletionStage future) { + return internalSpan(name, method, future); + } + + @Override + public Span span(final String path, final String method) { + return internalSpan(path, method, null); + } + + @Override + public Span span(final HttpRequest request) { + requireNonNull(request); + return internalSpan(request, null); + } + + @Override + public Span span(final HttpRequest request, final CompletionStage future) { + return internalSpan(request, future); + } + + protected abstract Span internalSpan(String path, String method, CompletionStage future); + + protected abstract Span internalSpan(HttpRequest request, CompletionStage future); + + @Override + public void attachSpanToFuture(final Span span, final CompletionStage future) { + future + .whenComplete( + (result, t) -> { + if (t == null) { + span.success(); + } else { + span.failure(t); + } + span.close(); + }) + .exceptionally( + t -> { + span.failure(t); + span.close(); + return null; + }); + } +} diff --git a/src/main/java/com/spotify/github/tracing/NoopTracer.java b/src/main/java/com/spotify/github/tracing/NoopTracer.java new file mode 100644 index 00000000..b921f897 --- /dev/null +++ b/src/main/java/com/spotify/github/tracing/NoopTracer.java @@ -0,0 +1,82 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.tracing; + + +import com.spotify.github.http.HttpRequest; +import java.util.concurrent.CompletionStage; + +public class NoopTracer extends BaseTracer { + + public static final NoopTracer INSTANCE = new NoopTracer(); + private static final Span SPAN = + new Span() { + @Override + public Span success() { + return this; + } + + @Override + public Span failure(final Throwable t) { + return this; + } + + @Override + public void close() {} + + @Override + public Span addTag(final String key, final String value) { + return this; + } + + @Override + public Span addTag(final String key, final boolean value) { + return this; + } + + @Override + public Span addTag(final String key, final long value) { + return this; + } + + @Override + public Span addTag(final String key, final double value) { + return this; + } + + @Override + public Span addEvent(final String description) { + return this; + } + }; + + private NoopTracer() {} + + @Override + protected Span internalSpan(final String path, final String method, final CompletionStage future) { + return SPAN; + } + + @Override + protected Span internalSpan(final HttpRequest request, final CompletionStage future) { + return SPAN; + } +} diff --git a/src/main/java/com/spotify/github/tracing/Span.java b/src/main/java/com/spotify/github/tracing/Span.java new file mode 100644 index 00000000..f5c1abdb --- /dev/null +++ b/src/main/java/com/spotify/github/tracing/Span.java @@ -0,0 +1,42 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.tracing; + +public interface Span extends AutoCloseable { + + Span success(); + + Span failure(Throwable t); + + /** Close span. Must be called for any opened span. */ + @Override + void close(); + + Span addTag(String key, String value); + + Span addTag(String key, boolean value); + + Span addTag(String key, long value); + + Span addTag(String key, double value); + + Span addEvent(String description); +} diff --git a/src/main/java/com/spotify/github/tracing/TraceHelper.java b/src/main/java/com/spotify/github/tracing/TraceHelper.java new file mode 100644 index 00000000..6c783067 --- /dev/null +++ b/src/main/java/com/spotify/github/tracing/TraceHelper.java @@ -0,0 +1,66 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.tracing; + +import com.spotify.github.v3.exceptions.RequestNotOkException; + +public class TraceHelper { + // Tracing Headers + public static final String HEADER_CLOUD_TRACE_CONTEXT = "X-Cloud-Trace-Context"; + public static final String HEADER_TRACE_PARENT = "traceparent"; + public static final String HEADER_TRACE_STATE = "tracestate"; + + public static final int NOT_FOUND = 404; + public static final int INTERNAL_SERVER_ERROR = 500; + + // Private constructor to prevent instantiation + private TraceHelper() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + public static Span failSpan(final Span span, final Throwable t) { + if (t instanceof RequestNotOkException) { + RequestNotOkException ex = (RequestNotOkException) t; + span.addTag(TraceHelper.TraceTags.HTTP_STATUS_CODE, ex.statusCode()) + .addTag(TraceHelper.TraceTags.ERROR_MESSAGE, ex.getRawMessage()); + if (ex.statusCode() - INTERNAL_SERVER_ERROR >= 0) { + span.addTag(TraceHelper.TraceTags.ERROR, true); + } + } else { + if (t != null) { + span.addTag(TraceHelper.TraceTags.ERROR_MESSAGE, t.getMessage()); + } + span.addTag(TraceHelper.TraceTags.ERROR, true); + } + return span; + } + + public static class TraceTags { + public static final String COMPONENT = "component"; + public static final String PEER_SERVICE = "peer.service"; + public static final String HTTP_URL = "http.url"; + public static final String HTTP_METHOD = "method"; + public static final String HTTP_STATUS_CODE = "http.status_code"; + public static final String HTTP_STATUS_MESSAGE = "http.status_message"; + public static final String ERROR_MESSAGE = "message"; + public static final String ERROR = "error"; + } +} diff --git a/src/main/java/com/spotify/github/tracing/Tracer.java b/src/main/java/com/spotify/github/tracing/Tracer.java new file mode 100644 index 00000000..afa3499c --- /dev/null +++ b/src/main/java/com/spotify/github/tracing/Tracer.java @@ -0,0 +1,38 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.tracing; + +import com.spotify.github.http.HttpRequest; +import java.util.concurrent.CompletionStage; + +public interface Tracer { + + /** Create scoped span. Span will be closed when future completes. */ + Span span(String path, String method, CompletionStage future); + + Span span(String path, String method); + + Span span(HttpRequest request); + + Span span(HttpRequest request, CompletionStage future); + + void attachSpanToFuture(Span span, CompletionStage future); +} diff --git a/src/main/java/com/spotify/github/tracing/opencensus/OpenCensusSpan.java b/src/main/java/com/spotify/github/tracing/opencensus/OpenCensusSpan.java new file mode 100644 index 00000000..755d0a0f --- /dev/null +++ b/src/main/java/com/spotify/github/tracing/opencensus/OpenCensusSpan.java @@ -0,0 +1,84 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.tracing.opencensus; + +import static com.spotify.github.tracing.TraceHelper.failSpan; +import static java.util.Objects.requireNonNull; + +import com.spotify.github.tracing.Span; +import io.opencensus.trace.AttributeValue; +import io.opencensus.trace.Status; + +public class OpenCensusSpan implements Span { + private final io.opencensus.trace.Span span; + + public OpenCensusSpan(final io.opencensus.trace.Span span) { + this.span = requireNonNull(span); + } + + @Override + public Span success() { + span.setStatus(Status.OK); + return this; + } + + @Override + public Span failure(final Throwable t) { + failSpan(this, t); + span.setStatus(Status.UNKNOWN); + return this; + } + + @Override + public void close() { + span.end(); + } + + @Override + public Span addTag(final String key, final String value) { + this.span.putAttribute(key, AttributeValue.stringAttributeValue(value)); + return this; + } + + @Override + public Span addTag(final String key, final boolean value) { + this.span.putAttribute(key, AttributeValue.booleanAttributeValue(value)); + return this; + } + + @Override + public Span addTag(final String key, final long value) { + this.span.putAttribute(key, AttributeValue.longAttributeValue(value)); + return this; + } + + @Override + public Span addTag(final String key, final double value) { + this.span.putAttribute(key, AttributeValue.doubleAttributeValue(value)); + return this; + } + + @Override + public Span addEvent(final String description) { + this.span.addAnnotation(description); + return this; + } +} diff --git a/src/main/java/com/spotify/github/tracing/opencensus/OpenCensusTracer.java b/src/main/java/com/spotify/github/tracing/opencensus/OpenCensusTracer.java new file mode 100644 index 00000000..6e7bb2c3 --- /dev/null +++ b/src/main/java/com/spotify/github/tracing/opencensus/OpenCensusTracer.java @@ -0,0 +1,66 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.tracing.opencensus; + +import static io.opencensus.trace.Span.Kind.CLIENT; +import static java.util.Objects.requireNonNull; + +import com.spotify.github.http.HttpRequest; +import com.spotify.github.tracing.BaseTracer; +import com.spotify.github.tracing.Span; +import com.spotify.github.tracing.TraceHelper; +import io.opencensus.trace.Tracing; +import java.util.concurrent.CompletionStage; +import okhttp3.*; + +/** Tracer implementation using OpenCensus. */ +public class OpenCensusTracer extends BaseTracer { + + private static final io.opencensus.trace.Tracer TRACER = Tracing.getTracer(); + + @SuppressWarnings("MustBeClosedChecker") + protected Span internalSpan( + final String path, final String method, final CompletionStage future) { + requireNonNull(path); + + final io.opencensus.trace.Span ocSpan = + TRACER.spanBuilder("GitHub Request").setSpanKind(CLIENT).startSpan(); + + final Span span = + new OpenCensusSpan(ocSpan) + .addTag(TraceHelper.TraceTags.COMPONENT, "github-api-client") + .addTag(TraceHelper.TraceTags.PEER_SERVICE, "github") + .addTag(TraceHelper.TraceTags.HTTP_URL, path) + .addTag(TraceHelper.TraceTags.HTTP_METHOD, method); + + if (future != null) { + attachSpanToFuture(span, future); + } + + return span; + } + + @Override + protected Span internalSpan(final HttpRequest request, final CompletionStage future) { + requireNonNull(request); + return internalSpan(request.url(), request.method(), future); + } +} diff --git a/src/main/java/com/spotify/github/tracing/opentelemetry/OpenTelemetrySpan.java b/src/main/java/com/spotify/github/tracing/opentelemetry/OpenTelemetrySpan.java new file mode 100644 index 00000000..66b1c493 --- /dev/null +++ b/src/main/java/com/spotify/github/tracing/opentelemetry/OpenTelemetrySpan.java @@ -0,0 +1,86 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.tracing.opentelemetry; + +import static com.spotify.github.tracing.TraceHelper.failSpan; +import static java.util.Objects.requireNonNull; + +import com.spotify.github.tracing.Span; +import io.opentelemetry.api.trace.StatusCode; + +public class OpenTelemetrySpan implements Span { + public static final int NOT_FOUND = 404; + public static final int INTERNAL_SERVER_ERROR = 500; + + private final io.opentelemetry.api.trace.Span span; + + public OpenTelemetrySpan(final io.opentelemetry.api.trace.Span span) { + this.span = requireNonNull(span); + } + + @Override + public Span success() { + span.setStatus(StatusCode.OK); + return this; + } + + @Override + public Span failure(final Throwable t) { + failSpan(this, t); + span.setStatus(StatusCode.ERROR); + return this; + } + + @Override + public void close() { + span.end(); + } + + @Override + public Span addTag(final String key, final String value) { + this.span.setAttribute(key, value); + return this; + } + + @Override + public Span addTag(final String key, final boolean value) { + this.span.setAttribute(key, value); + return this; + } + + @Override + public Span addTag(final String key, final long value) { + this.span.setAttribute(key, value); + return this; + } + + @Override + public Span addTag(final String key, final double value) { + this.span.setAttribute(key, value); + return this; + } + + @Override + public Span addEvent(final String description) { + this.span.addEvent(description); + return this; + } +} diff --git a/src/main/java/com/spotify/github/tracing/opentelemetry/OpenTelemetryTracer.java b/src/main/java/com/spotify/github/tracing/opentelemetry/OpenTelemetryTracer.java new file mode 100644 index 00000000..764ec5c2 --- /dev/null +++ b/src/main/java/com/spotify/github/tracing/opentelemetry/OpenTelemetryTracer.java @@ -0,0 +1,127 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2021 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.tracing.opentelemetry; + +import static java.util.Objects.requireNonNull; + +import com.spotify.github.http.HttpRequest; +import com.spotify.github.tracing.BaseTracer; +import com.spotify.github.tracing.Span; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapGetter; +import java.util.concurrent.CompletionStage; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** Tracer implementation using OpenTelemetry. */ +public class OpenTelemetryTracer extends BaseTracer { + private final io.opentelemetry.api.trace.Tracer tracer; + private final OpenTelemetry openTelemetry; + + public OpenTelemetryTracer(final OpenTelemetry openTelemetry) { + this.openTelemetry = openTelemetry; + this.tracer = openTelemetry.getTracer("github-java-client"); + } + + public OpenTelemetryTracer() { + this(GlobalOpenTelemetry.get()); + } + + public OpenTelemetry getOpenTelemetry() { + return openTelemetry; + } + + /** + * Create a new span for the given path and method. + * + * @param path The path of the request. + * @param method The method of the request. + * @param future The future to attach the span to. + * @return The created span. + */ + @SuppressWarnings("MustBeClosedChecker") + protected Span internalSpan( + final String path, final String method, final CompletionStage future) { + requireNonNull(path); + + Context context = Context.current(); + + final io.opentelemetry.api.trace.Span otSpan = + tracer + .spanBuilder("GitHub Request") + .setParent(context) + .setSpanKind(SpanKind.CLIENT) + .startSpan(); + + otSpan.setAttribute("component", "github-api-client"); + otSpan.setAttribute("peer.service", "github"); + otSpan.setAttribute("http.url", path); + otSpan.setAttribute("method", method); + final Span span = new OpenTelemetrySpan(otSpan); + + if (future == null) { + return span; + } else { + attachSpanToFuture(span, future); + } + return span; + } + + /** + * Create a new span for the given request. + * + * @param request The request to create a span for. + * @param future The future to attach the span to. + * @return The created span. + */ + @Override + protected Span internalSpan(final HttpRequest request, final CompletionStage future) { + requireNonNull(request); + // Extract the context from the request headers. + Context context = + W3CTraceContextPropagator.getInstance() + .extract( + Context.current(), + request, + new TextMapGetter<>() { + @Override + public Iterable keys(@NotNull final HttpRequest carrier) { + return carrier.headers().keySet(); + } + + @Nullable + @Override + public String get( + @Nullable final HttpRequest carrier, @NotNull final String key) { + if (carrier == null) { + return null; + } + return carrier.header(key); + } + }); + context.makeCurrent(); + return internalSpan(request.url(), request.method(), future); + } +} diff --git a/src/main/java/com/spotify/github/v3/activity/events/CreateEvent.java b/src/main/java/com/spotify/github/v3/activity/events/CreateEvent.java index 384784ad..f3ef02dd 100644 --- a/src/main/java/com/spotify/github/v3/activity/events/CreateEvent.java +++ b/src/main/java/com/spotify/github/v3/activity/events/CreateEvent.java @@ -47,7 +47,6 @@ public interface CreateEvent extends BaseEvent { String masterBranch(); /** The repository's current description. */ - @Nullable Optional description(); /** No doc found on github - Usually is "user". */ diff --git a/src/main/java/com/spotify/github/v3/activity/events/EventType.java b/src/main/java/com/spotify/github/v3/activity/events/EventType.java new file mode 100644 index 00000000..1081830e --- /dev/null +++ b/src/main/java/com/spotify/github/v3/activity/events/EventType.java @@ -0,0 +1,94 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.activity.events; + +public enum EventType { + BRANCH_PROTECTION_RULE, + CHECK_RUN, + CHECK_SUITE, + CODE_SCANNING_ALERT, + COMMIT_COMMENT, + CONTENT_REFERENCE, + CREATE, + DELETE, + DEPLOY_KEY, + DEPLOYMENT, + DEPLOYMENT_STATUS, + DISCUSSION, + DISCUSSION_COMMENT, + DOWNLOAD, + FOLLOW, + FORK, + FORK_APPLY, + GITHUB_APP_AUTHORIZATION, + GIST, + GOLLUM, + INSTALLATION, + INSTALLATION_REPOSITORIES, + INTEGRATION_INSTALLATION_REPOSITORIES, + ISSUE_COMMENT, + ISSUES, + LABEL, + MARKETPLACE_PURCHASE, + MEMBER, + MEMBERSHIP, + MERGE_QUEUE_ENTRY, + MERGE_GROUP, + META, + MILESTONE, + ORGANIZATION, + ORG_BLOCK, + PACKAGE, + PAGE_BUILD, + PROJECT_CARD, + PROJECT_COLUMN, + PROJECT, + PING, + PUBLIC, + PULL_REQUEST, + PULL_REQUEST_REVIEW, + PULL_REQUEST_REVIEW_COMMENT, + PULL_REQUEST_REVIEW_THREAD, + PUSH, + REGISTRY_PACKAGE, + RELEASE, + REPOSITORY_DISPATCH, + REPOSITORY, + REPOSITORY_IMPORT, + REPOSITORY_VULNERABILITY_ALERT, + SCHEDULE, + SECURITY_ADVISORY, + STAR, + STATUS, + TEAM, + TEAM_ADD, + WATCH, + WORKFLOW_JOB, + WORKFLOW_DISPATCH, + WORKFLOW_RUN, + UNKNOWN, + ALL; + + @Override + public String toString() { + return this.name().toLowerCase(); + } +} diff --git a/src/main/java/com/spotify/github/v3/activity/events/MergeGroup.java b/src/main/java/com/spotify/github/v3/activity/events/MergeGroup.java new file mode 100644 index 00000000..0666e0be --- /dev/null +++ b/src/main/java/com/spotify/github/v3/activity/events/MergeGroup.java @@ -0,0 +1,54 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.activity.events; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.GithubStyle; +import javax.annotation.Nullable; +import org.immutables.value.Value; + +/** + * Represents a merge group in GitHub's merge queue. + * A merge group is created when pull requests are added to a merge queue. + */ +@Value.Immutable +@GithubStyle +@JsonSerialize(as = ImmutableMergeGroup.class) +@JsonDeserialize(as = ImmutableMergeGroup.class) +public interface MergeGroup { + + /** The SHA of the merge group. */ + @Nullable + String headSha(); + + /** The full ref of the merge group. */ + @Nullable + String headRef(); + + /** The SHA of the merge group's parent commit. */ + @Nullable + String baseSha(); + + /** The full ref of the branch the merge group is merging into. */ + @Nullable + String baseRef(); +} diff --git a/src/main/java/com/spotify/github/v3/activity/events/MergeGroupEvent.java b/src/main/java/com/spotify/github/v3/activity/events/MergeGroupEvent.java new file mode 100644 index 00000000..d49251ad --- /dev/null +++ b/src/main/java/com/spotify/github/v3/activity/events/MergeGroupEvent.java @@ -0,0 +1,49 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.activity.events; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.GithubStyle; +import javax.annotation.Nullable; +import org.immutables.value.Value; + +/** + * Triggered when a pull request is added to a merge queue. + * The merge queue feature allows pull requests to be queued and merged automatically. + */ +@Value.Immutable +@GithubStyle +@JsonSerialize(as = ImmutableMergeGroupEvent.class) +@JsonDeserialize(as = ImmutableMergeGroupEvent.class) +public interface MergeGroupEvent extends BaseEvent { + + /** + * The action that was performed. Can be "checks_requested" when a merge group is created + * and checks are requested, or "destroyed" when the merge group is removed from the queue. + */ + @Nullable + String action(); + + /** The merge group. */ + @Nullable + MergeGroup mergeGroup(); +} diff --git a/src/main/java/com/spotify/github/v3/activity/events/PushEvent.java b/src/main/java/com/spotify/github/v3/activity/events/PushEvent.java index b6f2690a..06d33cb8 100644 --- a/src/main/java/com/spotify/github/v3/activity/events/PushEvent.java +++ b/src/main/java/com/spotify/github/v3/activity/events/PushEvent.java @@ -93,7 +93,6 @@ public interface PushEvent { List commits(); /** The push commit object of the most recent commit on ref after the push. */ - @Nullable Optional headCommit(); /** Pusher */ diff --git a/src/main/java/com/spotify/github/v3/activity/events/StatusEvent.java b/src/main/java/com/spotify/github/v3/activity/events/StatusEvent.java index a43123d1..35d0a1fd 100644 --- a/src/main/java/com/spotify/github/v3/activity/events/StatusEvent.java +++ b/src/main/java/com/spotify/github/v3/activity/events/StatusEvent.java @@ -66,7 +66,6 @@ public interface StatusEvent extends BaseEvent, UpdateTracking { String context(); /** The optional human-readable description added to the status. */ - @Nullable Optional description(); /** The new state. Can be pending, success, failure, or error. */ diff --git a/src/main/java/com/spotify/github/v3/apps/requests/AccessTokenRequest.java b/src/main/java/com/spotify/github/v3/apps/requests/AccessTokenRequest.java new file mode 100644 index 00000000..ede485da --- /dev/null +++ b/src/main/java/com/spotify/github/v3/apps/requests/AccessTokenRequest.java @@ -0,0 +1,53 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ +package com.spotify.github.v3.apps.requests; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.GithubStyle; +import java.util.List; +import java.util.Optional; +import org.immutables.value.Value; + +/** Request to create an installation access token with repository scoping. */ +@Value.Immutable +@GithubStyle +@JsonSerialize(as = ImmutableAccessTokenRequest.class) +@JsonDeserialize(as = ImmutableAccessTokenRequest.class) +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public interface AccessTokenRequest { + + /** + * List of repository names that the token should be scoped to. + * + * @return list of repository names + */ + Optional> repositories(); + + /** + * List of repository IDs that the token should be scoped to. + * + * @return list of repository IDs + */ + @JsonProperty("repository_ids") + Optional> repositoryIds(); +} diff --git a/src/main/java/com/spotify/github/v3/checks/App.java b/src/main/java/com/spotify/github/v3/checks/App.java index 8affe3a0..e130b754 100644 --- a/src/main/java/com/spotify/github/v3/checks/App.java +++ b/src/main/java/com/spotify/github/v3/checks/App.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.spotify.github.GithubStyle; +import com.spotify.github.v3.User; import java.time.ZonedDateTime; import java.util.List; import java.util.Map; @@ -112,4 +113,53 @@ public interface App { * @return the optional count */ Optional installationsCount(); + + /** + * The client ID of the GitHub App. + * + * @return the optional client ID + */ + Optional clientId(); + + /** + * The name of the single file the GitHub App can access (if applicable). + * + * @return the optional single file name + */ + Optional singleFileName(); + + /** + * Whether the GitHub App has access to multiple single files. + * + * @return the optional boolean + */ + Optional hasMultipleSingleFiles(); + + /** + * The list of single file paths the GitHub App can access. + * + * @return the optional list of file paths + */ + Optional> singleFilePaths(); + + /** + * The slug name of the GitHub App. + * + * @return the optional app slug + */ + Optional appSlug(); + + /** + * The date the App was suspended. + * + * @return the optional suspended date + */ + Optional suspendedAt(); + + /** + * The user who suspended the App. + * + * @return the optional user + */ + Optional suspendedBy(); } diff --git a/src/main/java/com/spotify/github/v3/checks/CheckRunResponse.java b/src/main/java/com/spotify/github/v3/checks/CheckRunResponse.java index 7b672a2a..3acd1379 100644 --- a/src/main/java/com/spotify/github/v3/checks/CheckRunResponse.java +++ b/src/main/java/com/spotify/github/v3/checks/CheckRunResponse.java @@ -22,7 +22,11 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.spotify.github.GithubStyle; + +import java.util.List; import java.util.Optional; + +import com.spotify.github.v3.prs.PartialPullRequestItem; import org.immutables.value.Value; /** The CheckRun response resource. */ @@ -73,4 +77,10 @@ public interface CheckRunResponse extends CheckRunBase { * @return the optional */ Optional app(); + + /** + * Pull Requests where this check is applied. + * @return the optional of list of pull requests + */ + Optional> pullRequests(); } diff --git a/src/main/java/com/spotify/github/v3/checks/CheckSuite.java b/src/main/java/com/spotify/github/v3/checks/CheckSuite.java index 380b8aee..ea13d811 100644 --- a/src/main/java/com/spotify/github/v3/checks/CheckSuite.java +++ b/src/main/java/com/spotify/github/v3/checks/CheckSuite.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,23 +22,34 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.spotify.github.GithubStyle; + +import java.util.List; import java.util.Optional; + +import com.spotify.github.v3.prs.PartialPullRequestItem; import org.immutables.value.Value; -/** Github CheckSuite */ +/** GitHub CheckSuite */ @Value.Immutable @GithubStyle @JsonDeserialize(as = ImmutableCheckSuite.class) public interface CheckSuite { /** - * The Check Suite Id. + * The Check Suite id. * - * @return the integer + * @return the long id */ Long id(); Optional app(); Optional headBranch(); + + /** + * Pull Requests where this check suite is applied. + * + * @return the list of pull requests + */ + List pullRequests(); } diff --git a/src/main/java/com/spotify/github/v3/clients/ActionsClient.java b/src/main/java/com/spotify/github/v3/clients/ActionsClient.java new file mode 100644 index 00000000..8dc25c86 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/clients/ActionsClient.java @@ -0,0 +1,46 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.clients; + +public class ActionsClient { + private final String owner; + private final String repo; + private final GitHubClient github; + + ActionsClient(final GitHubClient github, final String owner, final String repo) { + this.github = github; + this.owner = owner; + this.repo = repo; + } + + static ActionsClient create(final GitHubClient github, final String owner, final String repo) { + return new ActionsClient(github, owner, repo); + } + + /** + * Workflows API client + * + * @return Workflows API client + */ + public WorkflowsClient createWorkflowsClient() { + return WorkflowsClient.create(github, owner, repo); + } +} diff --git a/src/main/java/com/spotify/github/v3/clients/GitDataClient.java b/src/main/java/com/spotify/github/v3/clients/GitDataClient.java index 4953f47b..6f7fda03 100644 --- a/src/main/java/com/spotify/github/v3/clients/GitDataClient.java +++ b/src/main/java/com/spotify/github/v3/clients/GitDataClient.java @@ -188,6 +188,23 @@ public CompletableFuture createTagReference(final String tag, final S return createReference(format("refs/tags/%s", tag), sha); } + /** + * Update a git reference. + * + * @param ref reference name + * @param sha The SHA1 value to set the reference to + * @param force Indicates whether to force the update or to make sure the update is a fast-forward update. Setting + * this to false will make sure you're not overwriting work. + */ + public CompletableFuture updateReference(final String ref, final String sha, final boolean force) { + final String path = format(REFERENCE_URI, owner, repo, ref); + final ImmutableMap body = + of( + "sha", sha, + "force", Boolean.toString(force)); + return github.patch(path, github.json().toJsonUnchecked(body), Reference.class); + } + /** * Create an annotated tag. First it would create a tag reference and then create annotated tag * diff --git a/src/main/java/com/spotify/github/v3/clients/GitHubClient.java b/src/main/java/com/spotify/github/v3/clients/GitHubClient.java index 81a72bf9..b7809a47 100644 --- a/src/main/java/com/spotify/github/v3/clients/GitHubClient.java +++ b/src/main/java/com/spotify/github/v3/clients/GitHubClient.java @@ -21,94 +21,98 @@ package com.spotify.github.v3.clients; import static java.util.concurrent.CompletableFuture.completedFuture; -import static okhttp3.MediaType.parse; import com.fasterxml.jackson.core.type.TypeReference; -import com.spotify.github.Tracer; +import com.spotify.github.async.Async; +import com.spotify.github.http.HttpClient; +import com.spotify.github.http.HttpRequest; +import com.spotify.github.http.HttpResponse; +import com.spotify.github.http.ImmutableHttpRequest; +import com.spotify.github.http.okhttp.OkHttpHttpClient; import com.spotify.github.jackson.Json; +import com.spotify.github.tracing.NoopTracer; +import com.spotify.github.tracing.Tracer; import com.spotify.github.v3.Team; import com.spotify.github.v3.User; import com.spotify.github.v3.checks.AccessToken; +import com.spotify.github.v3.checks.Installation; import com.spotify.github.v3.comment.Comment; +import com.spotify.github.v3.comment.CommentReaction; import com.spotify.github.v3.exceptions.ReadOnlyRepositoryException; import com.spotify.github.v3.exceptions.RequestNotOkException; +import com.spotify.github.v3.git.FileItem; import com.spotify.github.v3.git.Reference; import com.spotify.github.v3.orgs.TeamInvitation; import com.spotify.github.v3.prs.PullRequestItem; import com.spotify.github.v3.prs.Review; import com.spotify.github.v3.prs.ReviewRequests; -import com.spotify.github.v3.repos.Branch; -import com.spotify.github.v3.repos.CommitItem; -import com.spotify.github.v3.repos.FolderContent; -import com.spotify.github.v3.repos.Repository; -import com.spotify.github.v3.repos.Status; -import com.spotify.github.v3.repos.RepositoryInvitation; - -import java.io.*; +import com.spotify.github.v3.repos.*; +import java.io.File; +import java.io.IOException; import java.lang.invoke.MethodHandles; import java.net.URI; import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; +import javax.annotation.Nullable; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; - import okhttp3.*; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Github client is a main communication entry point. Provides lower level communication + * GitHub client is a main communication entry point. Provides lower level communication * functionality as well as acts as a factory for the higher level API clients. */ public class GitHubClient { private static final int EXPIRY_MARGIN_IN_MINUTES = 5; + private static final int HTTP_NOT_FOUND = 404; private Tracer tracer = NoopTracer.INSTANCE; - static final Consumer IGNORE_RESPONSE_CONSUMER = (response) -> { - if (response.body() != null) { - response.body().close(); - } - }; - static final TypeReference> LIST_COMMENT_TYPE_REFERENCE = - new TypeReference<>() {}; - static final TypeReference> LIST_REPOSITORY = + static final Consumer IGNORE_RESPONSE_CONSUMER = + (response) -> { + if (response != null) { + response.close(); + } + }; + static final TypeReference> LIST_COMMENT_TYPE_REFERENCE = new TypeReference<>() {}; + static final TypeReference> LIST_COMMENT_REACTION_TYPE_REFERENCE = new TypeReference<>() {}; + static final TypeReference> LIST_REPOSITORY = new TypeReference<>() {}; static final TypeReference> LIST_COMMIT_TYPE_REFERENCE = new TypeReference<>() {}; static final TypeReference> LIST_REVIEW_TYPE_REFERENCE = new TypeReference<>() {}; static final TypeReference LIST_REVIEW_REQUEST_TYPE_REFERENCE = new TypeReference<>() {}; - static final TypeReference> LIST_STATUS_TYPE_REFERENCE = - new TypeReference<>() {}; + static final TypeReference> LIST_STATUS_TYPE_REFERENCE = new TypeReference<>() {}; static final TypeReference> LIST_FOLDERCONTENT_TYPE_REFERENCE = new TypeReference<>() {}; static final TypeReference> LIST_PR_TYPE_REFERENCE = new TypeReference<>() {}; - static final TypeReference> LIST_BRANCHES = - new TypeReference<>() {}; - static final TypeReference> LIST_REFERENCES = + static final TypeReference> + LIST_PR_COMMENT_TYPE_REFERENCE = new TypeReference<>() {}; + static final TypeReference> LIST_BRANCHES = new TypeReference<>() {}; + static final TypeReference> LIST_REFERENCES = new TypeReference<>() {}; + static final TypeReference> LIST_REPOSITORY_INVITATION = new TypeReference<>() {}; - static final TypeReference> LIST_REPOSITORY_INVITATION = new TypeReference<>() {}; - static final TypeReference> LIST_TEAMS = - new TypeReference<>() {}; + static final TypeReference> LIST_TEAMS = new TypeReference<>() {}; - static final TypeReference> LIST_TEAM_MEMBERS = - new TypeReference<>() {}; + static final TypeReference> LIST_TEAM_MEMBERS = new TypeReference<>() {}; static final TypeReference> LIST_PENDING_TEAM_INVITATIONS = new TypeReference<>() {}; + static final TypeReference> LIST_FILE_ITEMS = new TypeReference<>() {}; + private static final String GET_ACCESS_TOKEN_URL = "app/installations/%s/access_tokens"; private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @@ -121,7 +125,8 @@ public class GitHubClient { private final Optional graphqlUrl; private final Json json = Json.create(); - private final OkHttpClient client; + private final HttpClient client; + private Call.Factory callFactory; private final String token; private final byte[] privateKey; @@ -131,7 +136,7 @@ public class GitHubClient { private final Map installationTokens; private GitHubClient( - final OkHttpClient client, + final HttpClient client, final URI baseUrl, final URI graphqlUrl, final String accessToken, @@ -145,7 +150,25 @@ private GitHubClient( this.privateKey = privateKey; this.appId = appId; this.installationId = installationId; - this.installationTokens = new HashMap<>(); + this.installationTokens = new ConcurrentHashMap<>(); + } + + private GitHubClient( + final OkHttpClient client, + final URI baseUrl, + final URI graphqlUrl, + final String accessToken, + final byte[] privateKey, + final Integer appId, + final Integer installationId) { + this.baseUrl = baseUrl; + this.graphqlUrl = Optional.ofNullable(graphqlUrl); + this.token = accessToken; + this.client = new OkHttpHttpClient(client); + this.privateKey = privateKey; + this.appId = appId; + this.installationId = installationId; + this.installationTokens = new ConcurrentHashMap<>(); } /** @@ -183,7 +206,8 @@ public static GitHubClient create(final URI baseUrl, final File privateKey, fina * @param appId the github app ID * @return github api client */ - public static GitHubClient create(final URI baseUrl, final byte[] privateKey, final Integer appId) { + public static GitHubClient create( + final URI baseUrl, final byte[] privateKey, final Integer appId) { return new GitHubClient(new OkHttpClient(), baseUrl, null, null, privateKey, appId, null); } @@ -211,8 +235,12 @@ public static GitHubClient create( * @return github api client */ public static GitHubClient create( - final URI baseUrl, final byte[] privateKey, final Integer appId, final Integer installationId) { - return new GitHubClient(new OkHttpClient(), baseUrl, null, null, privateKey, appId, installationId); + final URI baseUrl, + final byte[] privateKey, + final Integer appId, + final Integer installationId) { + return new GitHubClient( + new OkHttpClient(), baseUrl, null, null, privateKey, appId, installationId); } /** @@ -242,11 +270,11 @@ public static GitHubClient create( * @return github api client */ public static GitHubClient create( - final OkHttpClient httpClient, - final URI baseUrl, - final URI graphqlUrl, - final File privateKey, - final Integer appId) { + final OkHttpClient httpClient, + final URI baseUrl, + final URI graphqlUrl, + final File privateKey, + final Integer appId) { return createOrThrow(httpClient, baseUrl, graphqlUrl, privateKey, appId, null); } @@ -260,15 +288,13 @@ public static GitHubClient create( * @return github api client */ public static GitHubClient create( - final OkHttpClient httpClient, - final URI baseUrl, - final byte[] privateKey, - final Integer appId) { + final OkHttpClient httpClient, + final URI baseUrl, + final byte[] privateKey, + final Integer appId) { return new GitHubClient(httpClient, baseUrl, null, null, privateKey, appId, null); } - - /** * Create a github api client with a given base URL and a path to a key. * @@ -297,11 +323,11 @@ public static GitHubClient create( * @return github api client */ public static GitHubClient create( - final OkHttpClient httpClient, - final URI baseUrl, - final byte[] privateKey, - final Integer appId, - final Integer installationId) { + final OkHttpClient httpClient, + final URI baseUrl, + final byte[] privateKey, + final Integer appId, + final Integer installationId) { return new GitHubClient(httpClient, baseUrl, null, null, privateKey, appId, installationId); } @@ -319,7 +345,110 @@ public static GitHubClient create( } public static GitHubClient create( - final OkHttpClient httpClient, final URI baseUrl, final URI graphqlUrl, final String token) { + final OkHttpClient httpClient, final URI baseUrl, final URI graphqlUrl, final String token) { + return new GitHubClient(httpClient, baseUrl, graphqlUrl, token, null, null, null); + } + + /** + * Create a github api client with a given base URL and a path to a key. + * + * @param httpClient an instance of OkHttpClient + * @param baseUrl base URL + * @param privateKey the private key PEM file + * @param appId the github app ID + * @return github api client + */ + public static GitHubClient create( + final HttpClient httpClient, final URI baseUrl, final File privateKey, final Integer appId) { + return createOrThrow(httpClient, baseUrl, null, privateKey, appId, null); + } + + /** + * Create a github api client with a given base URL and a path to a key. + * + * @param httpClient an instance of OkHttpClient + * @param baseUrl base URL + * @param privateKey the private key PEM file + * @param appId the github app ID + * @return github api client + */ + public static GitHubClient create( + final HttpClient httpClient, + final URI baseUrl, + final URI graphqlUrl, + final File privateKey, + final Integer appId) { + return createOrThrow(httpClient, baseUrl, graphqlUrl, privateKey, appId, null); + } + + /** + * Create a github api client with a given base URL and a path to a key. + * + * @param httpClient an instance of OkHttpClient + * @param baseUrl base URL + * @param privateKey the private key as byte array + * @param appId the github app ID + * @return github api client + */ + public static GitHubClient create( + final HttpClient httpClient, + final URI baseUrl, + final byte[] privateKey, + final Integer appId) { + return new GitHubClient(httpClient, baseUrl, null, null, privateKey, appId, null); + } + + /** + * Create a github api client with a given base URL and a path to a key. + * + * @param httpClient an instance of OkHttpClient + * @param baseUrl base URL + * @param privateKey the private key PEM file + * @param appId the github app ID + * @return github api client + */ + public static GitHubClient create( + final HttpClient httpClient, + final URI baseUrl, + final File privateKey, + final Integer appId, + final Integer installationId) { + return createOrThrow(httpClient, baseUrl, null, privateKey, appId, installationId); + } + + /** + * Create a github api client with a given base URL and a path to a key. + * + * @param httpClient an instance of OkHttpClient + * @param baseUrl base URL + * @param privateKey the private key as byte array + * @param appId the github app ID + * @return github api client + */ + public static GitHubClient create( + final HttpClient httpClient, + final URI baseUrl, + final byte[] privateKey, + final Integer appId, + final Integer installationId) { + return new GitHubClient(httpClient, baseUrl, null, null, privateKey, appId, installationId); + } + + /** + * Create a github api client with a given base URL and authorization token. + * + * @param httpClient an instance of OkHttpClient + * @param baseUrl base URL + * @param token authorization token + * @return github api client + */ + public static GitHubClient create( + final HttpClient httpClient, final URI baseUrl, final String token) { + return new GitHubClient(httpClient, baseUrl, null, token, null, null, null); + } + + public static GitHubClient create( + final HttpClient httpClient, final URI baseUrl, final URI graphqlUrl, final String token) { return new GitHubClient(httpClient, baseUrl, graphqlUrl, token, null, null, null); } @@ -345,30 +474,49 @@ public static GitHubClient scopeForInstallationId( installationId); } - static String responseBodyUnchecked(final Response response) { - try (ResponseBody body = response.body()) { - return body.string(); - } catch (IOException e) { - throw new UncheckedIOException("Failed getting response body for: " + response, e); - } - } - public GitHubClient withScopeForInstallationId(final int installationId) { if (Optional.ofNullable(privateKey).isEmpty()) { throw new RuntimeException("Installation ID scoped client needs a private key"); } return new GitHubClient( - client, - baseUrl, - graphqlUrl.orElse(null), - null, - privateKey, - appId, - installationId); + client, baseUrl, graphqlUrl.orElse(null), null, privateKey, appId, installationId); + } + + /** + * This is for clients authenticated as a GitHub App: when performing operations, the + * "installation" of the App must be specified. This returns a {@code GitHubClient} that has been + * scoped to the user's/organization's installation of the app, if any. + */ + public CompletionStage> asAppScopedClient(final String owner) { + return Async.exceptionallyCompose( + this.createOrganisationClient(owner) + .createGithubAppClient() + .getInstallation() + .thenApply(Installation::id), + e -> { + if (e.getCause() instanceof RequestNotOkException + && ((RequestNotOkException) e.getCause()).statusCode() == HTTP_NOT_FOUND) { + return this.createUserClient(owner) + .createGithubAppClient() + .getUserInstallation() + .thenApply(Installation::id); + } + return CompletableFuture.failedFuture(e); + }) + .thenApply(id -> Optional.of(this.withScopeForInstallationId(id))) + .exceptionally( + e -> { + if (e.getCause() instanceof RequestNotOkException + && ((RequestNotOkException) e.getCause()).statusCode() == HTTP_NOT_FOUND) { + return Optional.empty(); + } + throw new RuntimeException(e); + }); } public GitHubClient withTracer(final Tracer tracer) { this.tracer = tracer; + this.client.setTracer(tracer); return this; } @@ -432,79 +580,77 @@ public OrganisationClient createOrganisationClient(final String org) { } /** - * Create user API client - * - * @return user API client - */ + * Create user API client + * + * @return user API client + */ public UserClient createUserClient(final String owner) { return UserClient.create(this, owner); } + /** + * Create GitHub App API client + * + * @return GitHub App API client + */ + public GithubAppClient createGithubAppClient() { + return new GithubAppClient(this); + } + Json json() { return json; } /** - * Make an http GET request for the given path on the server + * Make a http GET request for the given path on the server * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @return response body as a String */ - CompletableFuture request(final String path) { - final Request request = requestBuilder(path).build(); - log.debug("Making request to {}", request.url().toString()); - return call(request); + CompletableFuture request(final String path) { + return call("GET", path); } /** - * Make an http GET request for the given path on the server + * Make a http GET request for the given path on the server * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param extraHeaders extra github headers to be added to the call * @return a reader of response body */ - CompletableFuture request(final String path, final Map extraHeaders) { - final Request.Builder builder = requestBuilder(path); - extraHeaders.forEach(builder::addHeader); - final Request request = builder.build(); - log.debug("Making request to {}", request.url().toString()); - return call(request); + CompletableFuture request( + final String path, final Map extraHeaders) { + return call("GET", path, extraHeaders); } /** - * Make an http GET request for the given path on the server + * Make a http GET request for the given path on the server * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @return body deserialized as provided type */ CompletableFuture request(final String path, final Class clazz) { - final Request request = requestBuilder(path).build(); - log.debug("Making request to {}", request.url().toString()); - return call(request) - .thenApply(body -> json().fromJsonUncheckedNotNull(responseBodyUnchecked(body), clazz)); + return call(path) + .thenApply(response -> json().fromJsonUncheckedNotNull(response.bodyString(), clazz)); } /** - * Make an http GET request for the given path on the server + * Make a http GET request for the given path on the server * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param extraHeaders extra github headers to be added to the call * @return body deserialized as provided type */ CompletableFuture request( final String path, final Class clazz, final Map extraHeaders) { - final Request.Builder builder = requestBuilder(path); - extraHeaders.forEach(builder::addHeader); - final Request request = builder.build(); - log.debug("Making request to {}", request.url().toString()); - return call(request) - .thenApply(body -> json().fromJsonUncheckedNotNull(responseBodyUnchecked(body), clazz)); + return call("GET", path, null, extraHeaders) + .thenApply(response -> json().fromJsonUncheckedNotNull(response.bodyString(), clazz)); } /** - * Make an http request for the given path on the Github server. + * Make a http request for the given path on the GitHub server. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param extraHeaders extra github headers to be added to the call * @return body deserialized as provided type */ @@ -512,70 +658,51 @@ CompletableFuture request( final String path, final TypeReference typeReference, final Map extraHeaders) { - final Request.Builder builder = requestBuilder(path); - extraHeaders.forEach(builder::addHeader); - final Request request = builder.build(); - log.debug("Making request to {}", request.url().toString()); - return call(request) + return call("GET", path, null, extraHeaders) .thenApply( - response -> - json().fromJsonUncheckedNotNull(responseBodyUnchecked(response), typeReference)); + response -> json().fromJsonUncheckedNotNull(response.bodyString(), typeReference)); } /** - * Make an http request for the given path on the Github server. + * Make a http request for the given path on the GitHub server. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @return body deserialized as provided type */ CompletableFuture request(final String path, final TypeReference typeReference) { - final Request request = requestBuilder(path).build(); - log.debug("Making request to {}", request.url().toString()); - return call(request) + return call(path) .thenApply( - response -> - json().fromJsonUncheckedNotNull(responseBodyUnchecked(response), typeReference)); + response -> json().fromJsonUncheckedNotNull(response.bodyString(), typeReference)); } /** - * Make an http POST request for the given path with provided JSON body. + * Make a http POST request for the given path with provided JSON body. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param data request body as stringified JSON * @return response body as String */ - CompletableFuture post(final String path, final String data) { - final Request request = - requestBuilder(path) - .method("POST", RequestBody.create(parse(MediaType.APPLICATION_JSON), data)) - .build(); - log.debug("Making POST request to {}", request.url().toString()); - return call(request); + CompletableFuture post(final String path, final String data) { + return call("POST", path, data); } /** - * Make an http POST request for the given path with provided JSON body. + * Make a http POST request for the given path with provided JSON body. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param data request body as stringified JSON * @param extraHeaders * @return response body as String */ - CompletableFuture post( + CompletableFuture post( final String path, final String data, final Map extraHeaders) { - final Request.Builder builder = - requestBuilder(path) - .method("POST", RequestBody.create(parse(MediaType.APPLICATION_JSON), data)); - extraHeaders.forEach(builder::addHeader); - final Request request = builder.build(); - log.debug("Making POST request to {}", request.url().toString()); - return call(request); + return call("POST", path, data, extraHeaders); } /** - * Make an http POST request for the given path with provided JSON body. + * Make a http POST request for the given path with provided JSON body. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param data request body as stringified JSON * @param clazz class to cast response as * @param extraHeaders @@ -587,105 +714,92 @@ CompletableFuture post( final Class clazz, final Map extraHeaders) { return post(path, data, extraHeaders) - .thenApply( - response -> json().fromJsonUncheckedNotNull(responseBodyUnchecked(response), clazz)); + .thenApply(response -> json().fromJsonUncheckedNotNull(response.bodyString(), clazz)); } /** - * Make an http POST request for the given path with provided JSON body. + * Make a http POST request for the given path with provided JSON body. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param data request body as stringified JSON * @param clazz class to cast response as * @return response body deserialized as provided class */ CompletableFuture post(final String path, final String data, final Class clazz) { return post(path, data) - .thenApply( - response -> json().fromJsonUncheckedNotNull(responseBodyUnchecked(response), clazz)); + .thenApply(response -> json().fromJsonUncheckedNotNull(response.bodyString(), clazz)); } /** - * Make a POST request to the graphql endpoint of Github + * Make a POST request to the graphql endpoint of GitHub * * @param data request body as stringified JSON * @return response - * - * @see "https://docs.github.com/en/enterprise-server@3.9/graphql/guides/forming-calls-with-graphql#communicating-with-graphql" + * @see + * "https://docs.github.com/en/enterprise-server@3.9/graphql/guides/forming-calls-with-graphql#communicating-with-graphql" */ - public CompletableFuture postGraphql(final String data) { - final Request request = - graphqlRequestBuilder() - .method("POST", RequestBody.create(parse(MediaType.APPLICATION_JSON), data)) - .build(); - log.info("Making POST request to {}", request.url()); - return call(request); + public CompletableFuture postGraphql(final String data) { + return graphqlRequestBuilder() + .thenCompose( + requestBuilder -> { + final HttpRequest request = requestBuilder.method("POST").body(data).build(); + log.info("Making POST request to {}", request.url()); + return call(request); + }); } /** - * Make an http PUT request for the given path with provided JSON body. + * Make a http PUT request for the given path with provided JSON body. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param data request body as stringified JSON * @return response body as String */ - CompletableFuture put(final String path, final String data) { - final Request request = - requestBuilder(path) - .method("PUT", RequestBody.create(parse(MediaType.APPLICATION_JSON), data)) - .build(); - log.debug("Making POST request to {}", request.url().toString()); - return call(request); + CompletableFuture put(final String path, final String data) { + return call("PUT", path, data); } /** * Make a HTTP PUT request for the given path with provided JSON body. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param data request body as stringified JSON * @param clazz class to cast response as * @return response body deserialized as provided class */ CompletableFuture put(final String path, final String data, final Class clazz) { return put(path, data) - .thenApply( - response -> json().fromJsonUncheckedNotNull(responseBodyUnchecked(response), clazz)); + .thenApply(response -> json().fromJsonUncheckedNotNull(response.bodyString(), clazz)); } /** - * Make an http PATCH request for the given path with provided JSON body. + * Make a http PATCH request for the given path with provided JSON body. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param data request body as stringified JSON * @return response body as String */ - CompletableFuture patch(final String path, final String data) { - final Request request = - requestBuilder(path) - .method("PATCH", RequestBody.create(parse(MediaType.APPLICATION_JSON), data)) - .build(); - log.debug("Making PATCH request to {}", request.url().toString()); - return call(request); + CompletableFuture patch(final String path, final String data) { + return call("PATCH", path, data); } /** - * Make an http PATCH request for the given path with provided JSON body. + * Make a http PATCH request for the given path with provided JSON body. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param data request body as stringified JSON * @param clazz class to cast response as * @return response body deserialized as provided class */ CompletableFuture patch(final String path, final String data, final Class clazz) { return patch(path, data) - .thenApply( - response -> json().fromJsonUncheckedNotNull(responseBodyUnchecked(response), clazz)); + .thenApply(response -> json().fromJsonUncheckedNotNull(response.bodyString(), clazz)); } /** - * Make an http PATCH request for the given path with provided JSON body + * Make a http PATCH request for the given path with provided JSON body * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param data request body as stringified JSON * @param clazz class to cast response as * @return response body deserialized as provided class @@ -695,47 +809,110 @@ CompletableFuture patch( final String data, final Class clazz, final Map extraHeaders) { - final Request.Builder builder = - requestBuilder(path) - .method("PATCH", RequestBody.create(parse(MediaType.APPLICATION_JSON), data)); - extraHeaders.forEach(builder::addHeader); - final Request request = builder.build(); - log.debug("Making PATCH request to {}", request.url().toString()); - return call(request) - .thenApply( - response -> json().fromJsonUncheckedNotNull(responseBodyUnchecked(response), clazz)); + return call("PATCH", path, data, extraHeaders) + .thenApply(response -> json().fromJsonUncheckedNotNull(response.bodyString(), clazz)); } /** - * Make an http DELETE request for the given path. + * Make a http DELETE request for the given path. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @return response body as String */ - CompletableFuture delete(final String path) { - final Request request = requestBuilder(path).delete().build(); - log.debug("Making DELETE request to {}", request.url().toString()); - return call(request); + CompletableFuture delete(final String path) { + return call("DELETE", path); } /** - * Make an http DELETE request for the given path. + * Make a http DELETE request for the given path. * - * @param path relative to the Github base url + * @param path relative to the GitHub base url * @param data request body as stringified JSON * @return response body as String */ - CompletableFuture delete(final String path, final String data) { - final Request request = - requestBuilder(path) - .method("DELETE", RequestBody.create(parse(MediaType.APPLICATION_JSON), data)) - .build(); - log.debug("Making DELETE request to {}", request.url().toString()); - return call(request); + CompletableFuture delete(final String path, final String data) { + return call("DELETE", path, data); + } + + /** + * Make a http DELETE request for the given path. + * + * @param path relative to the GitHub base url + * @return response body as String + */ + private CompletableFuture call(final String path) { + return call("GET", path, null, null); + } + + /** + * Make a http request for the given path on the GitHub server. + * + * @param method HTTP method + * @param path relative to the GitHub base url + * @return response body as String + */ + private CompletableFuture call(final String method, final String path) { + return call(method, path, null, null); } /** - * Create a URL for a given path to this Github server. + * Make a http request for the given path on the GitHub server. + * + * @param method HTTP method + * @param path relative to the GitHub base url + * @param extraHeaders extra github headers to be added to the call + * @return response body as String + */ + private CompletableFuture call( + final String method, final String path, final Map extraHeaders) { + return call(method, path, null, extraHeaders); + } + + /* + * Make a http request for the given path on the GitHub server. + * + * @param method HTTP method + * @param path relative to the GitHub base url + * @param data request body as stringified JSON + * @return response body as String + */ + private CompletableFuture call( + final String method, final String path, final String data) { + return call(method, path, data, null); + } + + /** + * Make a http request for the given path on the GitHub server. + * + * @param method HTTP method + * @param path relative to the GitHub base url + * @param data request body as stringified JSON + * @param extraHeaders extra github headers to be added to the call + * @return response body as String + */ + private CompletableFuture call( + final String method, + final String path, + @Nullable final String data, + @Nullable final Map extraHeaders) { + return requestBuilder(path) + .thenCompose( + requestBuilder -> { + final ImmutableHttpRequest.Builder builder = requestBuilder.method(method); + if (data != null) { + builder.body(data); + } + final HttpRequest request = + extraHeaders == null || extraHeaders.isEmpty() + ? builder.build() + : toHttpRequestHeaders(builder, extraHeaders).build(); + log.debug("Making {} request to {}", method, request.url().toString()); + return call(request); + }); + } + + /** + * Create a URL for a given path to this GitHub server. * * @param path relative URI * @return URL to path on this server @@ -744,47 +921,83 @@ String urlFor(final String path) { return baseUrl.toString().replaceAll("/+$", "") + "/" + path.replaceAll("^/+", ""); } - private Request.Builder requestBuilder(final String path) { - final Request.Builder builder = - new Request.Builder() - .url(urlFor(path)) - .addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); - builder.addHeader(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(path)); - + /** + * Adds extra headers to the Request Builder + * + * @param builder the request builder + * @param extraHeaders the extra headers to be added + * @return the request builder with the extra headers + */ + private ImmutableHttpRequest.Builder toHttpRequestHeaders( + final ImmutableHttpRequest.Builder builder, final Map extraHeaders) { + HttpRequest request = builder.build(); + + extraHeaders.forEach( + (headerKey, headerValue) -> { + if (request.headers().containsKey(headerKey)) { + List headers = new ArrayList<>(request.headers().get(headerKey)); + headers.add(headerValue); + builder.putHeaders(headerKey, headers); + } else { + builder.putHeaders(headerKey, List.of(headerValue)); + } + }); return builder; } - private Request.Builder graphqlRequestBuilder() { + /* + * Create a Request Builder for this GitHub GraphQL server. + * + * @return GraphQL Request Builder + */ + private CompletableFuture graphqlRequestBuilder() { URI url = graphqlUrl.orElseThrow(() -> new IllegalStateException("No graphql url set")); - final Request.Builder builder = - new Request.Builder() - .url(url.toString()) - .addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); - builder.addHeader(HttpHeaders.AUTHORIZATION, getAuthorizationHeader("/graphql")); - return builder; + return requestBuilder("/graphql") + .thenApply(requestBuilder -> requestBuilder.url(url.toString())); + } + + /* + * Create a Request Builder for this GitHub server. + * + * @param path relative URI + * @return Request Builder + */ + private CompletableFuture requestBuilder(final String path) { + return getAuthorizationHeader(path) + .thenApply( + authHeader -> + ImmutableHttpRequest.builder() + .url(urlFor(path)) + .method("GET") + .body("") + .putHeaders(HttpHeaders.ACCEPT, List.of(MediaType.APPLICATION_JSON)) + .putHeaders(HttpHeaders.CONTENT_TYPE, List.of(MediaType.APPLICATION_JSON)) + .putHeaders(HttpHeaders.AUTHORIZATION, List.of(authHeader))); } + /* + * Check if the GraphQL API is enabled for this client. + * + * @return true if the GraphQL API is enabled, false otherwise + */ public boolean isGraphqlEnabled() { return graphqlUrl.isPresent(); } - /* Generates the Authentication header, given the API endpoint and the credentials provided. -

Github Requests can be authenticated in 3 different ways. +

GitHub Requests can be authenticated in 3 different ways. (1) Regular, static access token; - (2) JWT Token, generated from a private key. Used in Github Apps; - (3) Installation Token, generated from the JWT token. Also used in Github Apps. + (2) JWT Token, generated from a private key. Used in GitHub Apps; + (3) Installation Token, generated from the JWT token. Also used in GitHub Apps. */ - private String getAuthorizationHeader(final String path) { + private CompletableFuture getAuthorizationHeader(final String path) { if (isJwtRequest(path) && getPrivateKey().isEmpty()) { throw new IllegalStateException("This endpoint needs a client with a private key for an App"); } if (getAccessToken().isPresent()) { - return String.format("token %s", token); + return completedFuture(String.format("token %s", token)); } else if (getPrivateKey().isPresent()) { final String jwtToken; try { @@ -793,13 +1006,18 @@ private String getAuthorizationHeader(final String path) { throw new RuntimeException("There was an error generating JWT token", e); } if (isJwtRequest(path)) { - return String.format("Bearer %s", jwtToken); + return completedFuture(String.format("Bearer %s", jwtToken)); } if (installationId == null) { throw new RuntimeException("This endpoint needs a client with an installation ID"); } try { - return String.format("token %s", getInstallationToken(jwtToken, installationId)); + return getInstallationToken(jwtToken, installationId) + .thenApply(token -> String.format("token %s", token)) + .exceptionally( + ex -> { + throw new RuntimeException("Could not generate access token for github app", ex); + }); } catch (Exception e) { throw new RuntimeException("Could not generate access token for github app", e); } @@ -808,144 +1026,237 @@ private String getAuthorizationHeader(final String path) { } private boolean isJwtRequest(final String path) { - return path.startsWith("/app/installation") || path.endsWith("installation"); + return path.equals("/app") + || path.startsWith("/app/installation") + || path.endsWith("installation"); } - private String getInstallationToken(final String jwtToken, final int installationId) - throws Exception { + /** + * Fetches installation token from the cache or from the server if it is expired. + * + * @param jwtToken the JWT token + * @param installationId the installation ID + * @return a CompletableFuture with the installation token + */ + private CompletableFuture getInstallationToken( + final String jwtToken, final int installationId) { AccessToken installationToken = installationTokens.get(installationId); if (installationToken == null || isExpired(installationToken)) { log.info( - "Github token for installation {} is either expired or null. Trying to get a new one.", + "GitHub token for installation {} is either expired or null. Trying to get a new one.", installationId); - installationToken = generateInstallationToken(jwtToken, installationId); - installationTokens.put(installationId, installationToken); + return generateInstallationToken(jwtToken, installationId) + .thenApply( + accessToken -> { + installationTokens.put(installationId, accessToken); + return accessToken.token(); + }); } - return installationToken.token(); + return completedFuture(installationToken.token()); } + /** + * Check if the token is expired. + * + * @param token the access token + * @return true if the token is expired, false otherwise + */ private boolean isExpired(final AccessToken token) { // Adds a few minutes to avoid making calls with an expired token due to clock differences return token.expiresAt().isBefore(ZonedDateTime.now().plusMinutes(EXPIRY_MARGIN_IN_MINUTES)); } - private AccessToken generateInstallationToken(final String jwtToken, final int installationId) - throws Exception { - log.info("Got JWT Token. Now getting Github access_token for installation {}", installationId); + /** + * Generates the installation token for a given installation ID. + * + * @param jwtToken the JWT token + * @param installationId the installation ID + * @return a CompletableFuture with the access token + */ + private CompletableFuture generateInstallationToken( + final String jwtToken, final int installationId) { + log.info("Got JWT Token. Now getting GitHub access_token for installation {}", installationId); final String url = String.format(urlFor(GET_ACCESS_TOKEN_URL), installationId); - final Request request = - new Request.Builder() - .addHeader("Accept", "application/vnd.github.machine-man-preview+json") - .addHeader("Authorization", "Bearer " + jwtToken) + final HttpRequest request = + ImmutableHttpRequest.builder() .url(url) - .method("POST", RequestBody.create(parse(MediaType.APPLICATION_JSON), "")) + .putHeaders("Accept", List.of("application/vnd.github.machine-man-preview+json")) + .putHeaders("Authorization", List.of("Bearer " + jwtToken)) + .method("POST") + .body("") .build(); - final Response response = client.newCall(request).execute(); - - if (!response.isSuccessful()) { - throw new Exception( - String.format( - "Got non-2xx status %s when getting an access token from GitHub: %s", - response.code(), response.message())); - } - - if (response.body() == null) { - throw new Exception( - String.format( - "Got empty response body when getting an access token from GitHub, HTTP status was: %s", - response.message())); - } - final String text = response.body().string(); - response.body().close(); - return Json.create().fromJson(text, AccessToken.class); + return this.client + .send(request) + .thenApply( + response -> { + if (!response.isSuccessful()) { + throw new RuntimeException( + String.format( + "Got non-2xx status %s when getting an access token from GitHub: %s", + response.statusCode(), response.statusMessage())); + } + + if (response.bodyString() == null) { + throw new RuntimeException( + String.format( + "Got empty response body when getting an access token from GitHub, HTTP" + + " status was: %s", + response.statusMessage())); + } + final String text = response.bodyString(); + try { + return Json.create().fromJson(text, AccessToken.class); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .toCompletableFuture(); } - private CompletableFuture call(final Request request) { - final Call call = client.newCall(request); - - final CompletableFuture future = new CompletableFuture<>(); + private CompletableFuture call(final HttpRequest httpRequest) { + return this.client + .send(httpRequest) + .thenCompose(httpResponse -> handleResponse(httpRequest, httpResponse)); + } + /** + * Handle the response from the server. If the response is a redirect, redo the request with the + * new URL. + * + * @param httpRequest the original request + * @param httpResponse the response from the server + * @return a CompletableFuture with the processed response + */ + private CompletableFuture handleResponse( + final HttpRequest httpRequest, final HttpResponse httpResponse) { + final CompletableFuture future = new CompletableFuture<>(); // avoid multiple redirects final AtomicBoolean redirected = new AtomicBoolean(false); - - call.enqueue( - new Callback() { - @Override - public void onFailure(final Call call, final IOException e) { - future.completeExceptionally(e); - } - - @Override - public void onResponse(final Call call, final Response response) { - processPossibleRedirects(response, redirected) - .handle( - (res, ex) -> { - if (Objects.nonNull(ex)) { - future.completeExceptionally(ex); - } else if (!res.isSuccessful()) { - try { - future.completeExceptionally(mapException(res, request)); - } catch (final Throwable e) { - future.completeExceptionally(e); - } finally { - if (res.body() != null) { - res.body().close(); - } - } - } else { - future.complete(res); - } - return res; - }); - } - }); - tracer.span(request.url().toString(), request.method(), future); + processPossibleRedirects(httpResponse, redirected) + .handle( + (res, ex) -> { + if (Objects.nonNull(ex)) { + future.completeExceptionally(ex); + } else if (!res.isSuccessful()) { + try { + future.completeExceptionally(mapException(httpRequest, res)); + } catch (final Throwable e) { + future.completeExceptionally(e); + } + } else { + future.complete(res); + } + return res; + }) + .join(); return future; } - private RequestNotOkException mapException(final Response res, final Request request) - throws IOException { - String bodyString = res.body() != null ? res.body().string() : ""; - Map> headersMap = res.headers().toMultimap(); + /** + * Map the exception to a specific type based on the response status code. + * + * @param httpRequest the original request + * @param httpResponse the response from the server + * @return a RequestNotOkException with the appropriate type + */ + private RequestNotOkException mapException( + final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { + String bodyString = Optional.ofNullable(httpResponse.bodyString()).orElse(""); + Map> headersMap = httpResponse.headers(); - if (res.code() == FORBIDDEN) { + if (httpResponse.statusCode() == FORBIDDEN) { if (bodyString.contains("Repository was archived so is read-only")) { - return new ReadOnlyRepositoryException(request.method(), request.url().encodedPath(), res.code(), bodyString, headersMap); + return new ReadOnlyRepositoryException( + httpRequest.method(), + URI.create(httpRequest.url()).getPath(), + httpResponse.statusCode(), + bodyString, + headersMap); } } - return new RequestNotOkException(request.method(), request.url().encodedPath(), res.code(), bodyString, headersMap); + return new RequestNotOkException( + httpRequest.method(), + URI.create(httpRequest.url()).getPath(), + httpResponse.statusCode(), + bodyString, + headersMap); } - CompletableFuture processPossibleRedirects( - final Response response, final AtomicBoolean redirected) { - if (response.code() >= PERMANENT_REDIRECT - && response.code() <= TEMPORARY_REDIRECT + /** + * Process possible redirects. If the response is a redirect, redo the request with the new URL. + * + * @param response the response to process + * @param redirected a flag to indicate if a redirect has already occurred + * @return a CompletableFuture with the processed response + */ + CompletableFuture processPossibleRedirects( + final HttpResponse response, final AtomicBoolean redirected) { + if (response.statusCode() >= PERMANENT_REDIRECT + && response.statusCode() <= TEMPORARY_REDIRECT && !redirected.get()) { redirected.set(true); // redo the same request with a new URL - final String newLocation = response.header("Location"); - final Request request = - requestBuilder(newLocation) - .url(newLocation) - .method(response.request().method(), response.request().body()) - .build(); - // Do the new call and complete the original future when the new call completes - return call(request); + final String newLocation = response.headers().get("Location").get(0); + return requestBuilder(newLocation) + .thenCompose( + requestBuilder -> { + HttpRequest request = + requestBuilder + .url(newLocation) + .method(response.request().method()) + .body(response.request().body()) + .build(); + // Do the new call and complete the original future when the new call completes + return call(request); + }); } return completedFuture(response); } - /** - * Wrapper to Constructors that expose File object for the privateKey argument - * */ - private static GitHubClient createOrThrow(final OkHttpClient httpClient, final URI baseUrl, final URI graphqlUrl, final File privateKey, final Integer appId, final Integer installationId) { + /** Wrapper to Constructors that expose File object for the privateKey argument */ + private static GitHubClient createOrThrow( + final OkHttpClient httpClient, + final URI baseUrl, + final URI graphqlUrl, + final File privateKey, + final Integer appId, + final Integer installationId) { try { - return new GitHubClient(httpClient, baseUrl, graphqlUrl, null, FileUtils.readFileToByteArray(privateKey), appId, installationId); + return new GitHubClient( + httpClient, + baseUrl, + graphqlUrl, + null, + FileUtils.readFileToByteArray(privateKey), + appId, + installationId); + } catch (IOException e) { + throw new RuntimeException("There was an error generating JWT token", e); + } + } + + /** Wrapper to Constructors that expose File object for the privateKey argument */ + private static GitHubClient createOrThrow( + final HttpClient httpClient, + final URI baseUrl, + final URI graphqlUrl, + final File privateKey, + final Integer appId, + final Integer installationId) { + try { + return new GitHubClient( + httpClient, + baseUrl, + graphqlUrl, + null, + FileUtils.readFileToByteArray(privateKey), + appId, + installationId); } catch (IOException e) { throw new RuntimeException("There was an error generating JWT token", e); } diff --git a/src/main/java/com/spotify/github/v3/clients/GithubAppClient.java b/src/main/java/com/spotify/github/v3/clients/GithubAppClient.java index 02845801..aeb96094 100644 --- a/src/main/java/com/spotify/github/v3/clients/GithubAppClient.java +++ b/src/main/java/com/spotify/github/v3/clients/GithubAppClient.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,7 +23,9 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.google.common.collect.ImmutableMap; import com.spotify.github.v3.apps.InstallationRepositoriesResponse; +import com.spotify.github.v3.apps.requests.AccessTokenRequest; import com.spotify.github.v3.checks.AccessToken; +import com.spotify.github.v3.checks.App; import com.spotify.github.v3.checks.Installation; import java.util.List; import java.util.Map; @@ -34,6 +36,7 @@ /** Apps API client */ public class GithubAppClient { + private static final String GET_AUTHENTICATED_APP_URL = "/app"; private static final String GET_INSTALLATION_BY_ID_URL = "/app/installations/%s"; private static final String GET_ACCESS_TOKEN_URL = "/app/installations/%s/access_tokens"; private static final String GET_INSTALLATIONS_URL = "/app/installations?per_page=100"; @@ -48,7 +51,7 @@ public class GithubAppClient { private static final String GET_INSTALLATION_USER_URL = "/users/%s/installation"; private final GitHubClient github; - private final String owner; + private final Optional maybeOwner; private final Optional maybeRepo; private final Map extraHeaders = @@ -59,16 +62,38 @@ public class GithubAppClient { GithubAppClient(final GitHubClient github, final String owner, final String repo) { this.github = github; - this.owner = owner; + this.maybeOwner = Optional.of(owner); this.maybeRepo = Optional.of(repo); } GithubAppClient(final GitHubClient github, final String owner) { this.github = github; - this.owner = owner; + this.maybeOwner = Optional.of(owner); this.maybeRepo = Optional.empty(); } + GithubAppClient(final GitHubClient github) { + this.github = github; + this.maybeOwner = Optional.empty(); + this.maybeRepo = Optional.empty(); + } + + /** + * Gets the owner, throwing a descriptive exception if not present. + * + * @return the owner string + * @throws IllegalStateException if owner is not present + */ + private String requireOwner() { + return maybeOwner.orElseThrow( + () -> + new IllegalStateException( + "This operation requires an owner context. " + + "Use GitHubClient.createOrganisationClient(owner).createGithubAppClient() " + + "or GitHubClient.createRepositoryClient(owner, repo).createGithubAppClient() " + + "instead of GitHubClient.createGithubAppClient()")); + } + /** * List Installations of an app. * @@ -79,7 +104,7 @@ public CompletableFuture> getInstallations() { } /** - * Get Installation + * Get Installation of repo or org * * @return an Installation */ @@ -99,41 +124,60 @@ public CompletableFuture getInstallation(final Integer installatio /** * Get an installation of a repo + * * @return an Installation */ private CompletableFuture getRepoInstallation(final String repo) { return github.request( - String.format(GET_INSTALLATION_REPO_URL, owner, repo), Installation.class); + String.format(GET_INSTALLATION_REPO_URL, requireOwner(), repo), Installation.class); } /** * Get an installation of an org + * * @return an Installation */ private CompletableFuture getOrgInstallation() { return github.request( - String.format(GET_INSTALLATION_ORG_URL, owner), Installation.class); + String.format(GET_INSTALLATION_ORG_URL, requireOwner()), Installation.class); } - /** + /** * Get an installation of a user + * * @return an Installation */ public CompletableFuture getUserInstallation() { return github.request( - String.format(GET_INSTALLATION_USER_URL, owner), Installation.class); + String.format(GET_INSTALLATION_USER_URL, requireOwner()), Installation.class); } /** * Authenticates as an installation * * @return an Installation Token + * @see #getAccessToken(Integer, AccessTokenRequest) for repository-scoped tokens */ public CompletableFuture getAccessToken(final Integer installationId) { final String path = String.format(GET_ACCESS_TOKEN_URL, installationId); return github.post(path, "", AccessToken.class, extraHeaders); } + /** + * Authenticates as an installation with repository scoping. + * + * @param installationId the installation ID + * @param request the access token request with optional repository scoping + * @return an Installation Token + * @see "https://docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app" + */ + public CompletableFuture getAccessToken( + final Integer installationId, + final AccessTokenRequest request) { + final String path = String.format(GET_ACCESS_TOKEN_URL, installationId); + return github.post(path, github.json().toJsonUnchecked(request), AccessToken.class, extraHeaders); + } + /** * Lists the repositories that an app installation can access. * @@ -146,4 +190,17 @@ public CompletableFuture listAccessibleReposit return GitHubClient.scopeForInstallationId(github, installationId) .request(LIST_ACCESSIBLE_REPOS_URL, InstallationRepositoriesResponse.class, extraHeaders); } + + /** + * Get the authenticated GitHub App. + * + *

Returns the authenticated app. You must use a JWT to access this endpoint. + * + *

see https://docs.github.com/en/rest/apps/apps#get-the-authenticated-app + * + * @return the authenticated App + */ + public CompletableFuture getAuthenticatedApp() { + return github.request(GET_AUTHENTICATED_APP_URL, App.class); + } } diff --git a/src/main/java/com/spotify/github/v3/clients/GithubPage.java b/src/main/java/com/spotify/github/v3/clients/GithubPage.java index 6bbd4ad0..3e9e6c3a 100644 --- a/src/main/java/com/spotify/github/v3/clients/GithubPage.java +++ b/src/main/java/com/spotify/github/v3/clients/GithubPage.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,7 +20,6 @@ package com.spotify.github.v3.clients; -import static com.spotify.github.v3.clients.GitHubClient.responseBodyUnchecked; import static java.util.Arrays.stream; import static java.util.Objects.nonNull; import static java.util.function.Function.identity; @@ -37,8 +36,9 @@ import java.util.NoSuchElementException; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; -import okhttp3.ResponseBody; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.http.client.utils.URIBuilder; /** * Async page implementation for github resources @@ -47,12 +47,27 @@ */ public class GithubPage implements AsyncPage { + static final int ITEM_PER_PAGE_DEFAULT = 30; private final GitHubClient github; private final String path; private final TypeReference> typeReference; + private final int itemsPerPage; + + protected static String formatPath(final String path, final int itemsPerPage) { + try { + URIBuilder uriBuilder = new URIBuilder(path); + if (uriBuilder.getQueryParams().stream().anyMatch(p -> p.getName().equals("per_page"))) { + return path; + } + uriBuilder.addParameter("per_page", Integer.toString(itemsPerPage)); + return uriBuilder.toString(); + } catch (Exception e) { + return path; + } + } /** - * C'tor. + * Constructor. * * @param github github client * @param path resource page path @@ -60,8 +75,27 @@ public class GithubPage implements AsyncPage { */ GithubPage( final GitHubClient github, final String path, final TypeReference> typeReference) { + this.itemsPerPage = ITEM_PER_PAGE_DEFAULT; + this.github = github; + this.path = formatPath(path, ITEM_PER_PAGE_DEFAULT); + this.typeReference = typeReference; + } + + /** + * Constructor. + * + * @param github github client + * @param path resource page path + * @param typeReference type reference for deserialization + */ + GithubPage( + final GitHubClient github, + final String path, + final TypeReference> typeReference, + final int itemsPerPage) { + this.itemsPerPage = itemsPerPage; this.github = github; - this.path = path; + this.path = formatPath(path, itemsPerPage); this.typeReference = typeReference; } @@ -80,7 +114,7 @@ public CompletableFuture pagination() { .map( prevLink -> pageNumberFromUri(prevLink.url().toString()) - .orElseThrow( + .orElseThrow( () -> new RuntimeException( "Could not parse page number from Link header with rel=\"next\""))); @@ -94,7 +128,7 @@ public CompletableFuture pagination() { .map( lastLink -> pageNumberFromUri(lastLink.url().toString()) - .orElseThrow( + .orElseThrow( () -> new RuntimeException( "Could not parse page number from Link " @@ -124,7 +158,7 @@ public CompletableFuture> nextPage() { Optional.ofNullable(linkMap.get("next")) .map(nextLink -> nextLink.url().toString().replaceAll(github.urlFor(""), "")) .orElseThrow(() -> new NoSuchElementException("Page iteration exhausted")); - return new GithubPage<>(github, nextPath, typeReference); + return new GithubPage<>(github, nextPath, typeReference, itemsPerPage); }); } @@ -137,7 +171,7 @@ public CompletableFuture hasNextPage() { /** {@inheritDoc} */ @Override public AsyncPage clone() { - return new GithubPage<>(github, path, typeReference); + return new GithubPage<>(github, path, typeReference, itemsPerPage); } /** {@inheritDoc} */ @@ -147,9 +181,7 @@ public Iterator iterator() { .request(path) .thenApply( response -> - github - .json() - .fromJsonUncheckedNotNull(responseBodyUnchecked(response), typeReference)) + github.json().fromJsonUncheckedNotNull(response.bodyString(), typeReference)) .join() .iterator(); } @@ -158,20 +190,22 @@ private CompletableFuture> linkMapAsync() { return github .request(path) .thenApply( - response -> { - Optional.ofNullable(response.body()).ifPresent(ResponseBody::close); - return Optional.ofNullable(response.headers().get("Link")) - .map(linkHeader -> stream(linkHeader.split(","))) - .orElseGet(Stream::empty) + response -> + Optional.ofNullable(response.header("Link")).stream() + .flatMap(linkHeader -> stream(linkHeader.split(","))) .map(linkString -> Link.from(linkString.split(";"))) .filter(link -> link.rel().isPresent()) - .collect(toMap(link -> link.rel().get(), identity())); - }); + .collect(toMap(link -> link.rel().get(), identity()))); } - private Optional pageNumberFromUri(final String uri) { - return Optional.ofNullable(uri.replaceAll(".*\\?page=", "").replaceAll("&.*", "")) - .filter(string -> string.matches("\\d+")) - .map(Integer::parseInt); + protected static Optional pageNumberFromUri(final String uri) { + Pattern pageInQueryPattern = Pattern.compile("(^|\\?|&)page=(?\\d+)", Pattern.CASE_INSENSITIVE); + try { + String query = new URIBuilder(uri).build().getQuery(); + Matcher matcher = pageInQueryPattern.matcher(query); + return matcher.find() ? Optional.of(Integer.parseInt(matcher.group("page"))) : Optional.empty(); + } catch (Exception e) { + return Optional.empty(); + } } } diff --git a/src/main/java/com/spotify/github/v3/clients/IssueClient.java b/src/main/java/com/spotify/github/v3/clients/IssueClient.java index 1d965d27..7db3a41b 100644 --- a/src/main/java/com/spotify/github/v3/clients/IssueClient.java +++ b/src/main/java/com/spotify/github/v3/clients/IssueClient.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,12 +20,15 @@ package com.spotify.github.v3.clients; -import static com.spotify.github.v3.clients.GitHubClient.IGNORE_RESPONSE_CONSUMER; -import static com.spotify.github.v3.clients.GitHubClient.LIST_COMMENT_TYPE_REFERENCE; +import static com.spotify.github.v3.clients.GitHubClient.*; import com.google.common.collect.ImmutableMap; import com.spotify.github.async.AsyncPage; +import com.spotify.github.http.HttpResponse; import com.spotify.github.v3.comment.Comment; +import com.spotify.github.v3.comment.CommentReaction; +import com.spotify.github.v3.comment.CommentReactionContent; +import com.spotify.github.v3.issues.Issue; import java.lang.invoke.MethodHandles; import java.util.Iterator; import java.util.concurrent.CompletableFuture; @@ -35,94 +38,282 @@ /** Issue API client */ public class IssueClient { + // URI templates for various API endpoints static final String COMMENTS_URI_NUMBER_TEMPLATE = "/repos/%s/%s/issues/%s/comments"; static final String COMMENTS_URI_TEMPLATE = "/repos/%s/%s/issues/comments"; static final String COMMENTS_URI_ID_TEMPLATE = "/repos/%s/%s/issues/comments/%s"; + static final String COMMENTS_REACTION_TEMPLATE = "/repos/%s/%s/issues/comments/%s/reactions"; + static final String COMMENTS_REACTION_ID_TEMPLATE = "/repos/%s/%s/issues/comments/%s/reactions/%s"; + static final String ISSUES_REACTION_TEMPLATE = "/repos/%s/%s/issues/%s/reactions"; + static final String ISSUES_REACTION_ID_TEMPLATE = "/repos/%s/%s/issues/%s/reactions/%s"; + static final String ISSUES_URI_ID_TEMPLATE = "/repos/%s/%s/issues/%s"; private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private final GitHubClient github; private final String owner; private final String repo; + /** + * Constructs an IssueClient. + * @param github the GitHub client + * @param owner the repository owner + * @param repo the repository name + */ IssueClient(final GitHubClient github, final String owner, final String repo) { this.github = github; this.owner = owner; this.repo = repo; } + /** + * Creates an IssueClient. + * + * @param github the GitHub client + * @param owner the repository owner + * @param repo the repository name + * @return a new IssueClient instance + */ static IssueClient create(final GitHubClient github, final String owner, final String repo) { return new IssueClient(github, owner, repo); } /** - * List repository comments. + * Lists repository comments. * - * @return comments + * @return an iterator of asynchronous pages of comments */ public Iterator> listComments() { return listComments(String.format(COMMENTS_URI_TEMPLATE, owner, repo)); } /** - * List given issue number comments. + * Lists comments for a given issue number. * - * @param number issue number - * @return comments + * @param issueNumber the issue number + * @return an iterator of asynchronous pages of comments */ - public Iterator> listComments(final int number) { - return listComments(String.format(COMMENTS_URI_NUMBER_TEMPLATE, owner, repo, number)); + public Iterator> listComments(final long issueNumber) { + return listComments(String.format(COMMENTS_URI_NUMBER_TEMPLATE, owner, repo, issueNumber)); } /** - * Get a specific comment. + * Lists comments for a given issue number. * - * @param id comment id - * @return a comment + * @deprecated Use {@link #listComments(long)} instead + * @param issueNumber the issue number + * @return an iterator of asynchronous pages of comments */ - public CompletableFuture getComment(final int id) { - final String path = String.format(COMMENTS_URI_ID_TEMPLATE, owner, repo, id); + @Deprecated + public Iterator> listComments(final int issueNumber) { + return listComments((long) issueNumber); + } + + /** + * Gets a specific comment. + * + * @param commentId the comment id + * @return a CompletableFuture containing the comment + */ + public CompletableFuture getComment(final long commentId) { + final String path = String.format(COMMENTS_URI_ID_TEMPLATE, owner, repo, commentId); log.info("Fetching issue comments from " + path); return github.request(path, Comment.class); } /** - * Create a comment for a given issue number. + * Gets a specific comment. + * + * @deprecated Use {@link #getComment(long)} instead + * @param commentId the comment id + * @return a CompletableFuture containing the comment + */ + @Deprecated + public CompletableFuture getComment(final int commentId) { + return getComment((long) commentId); + } + + /** + * Creates a comment for a given issue number. * - * @param number issue number - * @param body comment content - * @return the Comment that was just created + * @param issueNumber the issue number + * @param body the comment content + * @return a CompletableFuture containing the created comment */ - public CompletableFuture createComment(final int number, final String body) { - final String path = String.format(COMMENTS_URI_NUMBER_TEMPLATE, owner, repo, number); + public CompletableFuture createComment(final long issueNumber, final String body) { + final String path = String.format(COMMENTS_URI_NUMBER_TEMPLATE, owner, repo, issueNumber); final String requestBody = github.json().toJsonUnchecked(ImmutableMap.of("body", body)); return github.post(path, requestBody, Comment.class); } /** - * Edit a specific comment. + * Creates a comment for a given issue number. + * + * @deprecated Use {@link #createComment(long, String)} instead + * @param issueNumber the issue number + * @param body the comment content + * @return a CompletableFuture containing the created comment + */ + @Deprecated + public CompletableFuture createComment(final int issueNumber, final String body) { + return createComment((long) issueNumber, body); + } + + /** + * Edits a specific comment. * - * @param id comment id - * @param body new comment content + * @param commentId the comment id + * @param body the new comment content + * @return a CompletableFuture representing the completion of the operation */ - public CompletableFuture editComment(final int id, final String body) { - final String path = String.format(COMMENTS_URI_ID_TEMPLATE, owner, repo, id); + public CompletableFuture editComment(final long commentId, final String body) { + final String path = String.format(COMMENTS_URI_ID_TEMPLATE, owner, repo, commentId); return github .patch(path, github.json().toJsonUnchecked(ImmutableMap.of("body", body))) .thenAccept(IGNORE_RESPONSE_CONSUMER); } /** - * Delete a comment. + * Edits a specific comment. * - * @param id comment id + * @deprecated Use {@link #editComment(long, String)} instead + * @param commentId the comment id + * @param body the new comment content + * @return a CompletableFuture representing the completion of the operation */ - public CompletableFuture deleteComment(final int id) { + @Deprecated + public CompletableFuture editComment(final int commentId, final String body) { + return editComment((long) commentId, body); + } + + /** + * Deletes a comment. + * + * @param commentId the comment id + * @return a CompletableFuture representing the completion of the operation + */ + public CompletableFuture deleteComment(final long commentId) { return github - .delete(String.format(COMMENTS_URI_ID_TEMPLATE, owner, repo, id)) + .delete(String.format(COMMENTS_URI_ID_TEMPLATE, owner, repo, commentId)) .thenAccept(IGNORE_RESPONSE_CONSUMER); } + /** + * Deletes a comment. + * + * @deprecated Use {@link #deleteComment(long)} instead + * @param commentId the comment id + * @return a CompletableFuture representing the completion of the operation + */ + @Deprecated + public CompletableFuture deleteComment(final int commentId) { + return deleteComment((long) commentId); + } + + /** + * Lists comments for a given path. + * + * @param path the API endpoint path + * @return an iterator of asynchronous pages of comments + */ private Iterator> listComments(final String path) { return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_COMMENT_TYPE_REFERENCE)); } + + /** + * Gets an issue by id. + * + * @param issueId the issue id + * @return a CompletableFuture containing the issue + */ + public CompletableFuture getIssue(final long issueId) { + return github.request(String.format(ISSUES_URI_ID_TEMPLATE, owner, repo, issueId), Issue.class); + } + + /** + * Gets an issue by id. + * + * @deprecated Use {@link #getIssue(long)} instead + * @param issueId the issue id + * @return a CompletableFuture containing the issue + */ + @Deprecated + public CompletableFuture getIssue(final int issueId) { + return getIssue((long) issueId); + } + + /** + * Creates a reaction on a comment. + * + * @param commentId the comment id + * @param reaction the reaction content + * @return a CompletableFuture containing the created reaction + */ + public CompletableFuture createCommentReaction( + final long commentId, final CommentReactionContent reaction) { + final String path = String.format(COMMENTS_REACTION_TEMPLATE, owner, repo, commentId); + final String requestBody = + github.json().toJsonUnchecked(ImmutableMap.of("content", reaction.toString())); + return github.post(path, requestBody, CommentReaction.class); + } + + /** + * Deletes a reaction on a comment. See List + * reactions for an issue comment + * + * @param commentId the comment id + * @param reactionId the reaction id + * @return a CompletableFuture containing the HTTP response + */ + public CompletableFuture deleteCommentReaction( + final long commentId, final long reactionId) { + final String path = + String.format(COMMENTS_REACTION_ID_TEMPLATE, owner, repo, commentId, reactionId); + return github.delete(path); + } + + /** + * Lists reactions on a comment. See List + * reactions for an issue comment + * + * @param commentId the comment id + * @return an iterator of asynchronous pages of comment reactions + */ + public GithubPageIterator listCommentReaction(final long commentId) { + final String path = String.format(COMMENTS_REACTION_TEMPLATE, owner, repo, commentId); + return new GithubPageIterator<>( + new GithubPage<>(github, path, LIST_COMMENT_REACTION_TYPE_REFERENCE)); + } + + /** + * Creates a reaction on an issue. + * + * @param issueNumber the issue number + * @param reaction the reaction content + * @return a CompletableFuture containing the created reaction + */ + public CompletableFuture createIssueReaction( + final long issueNumber, final CommentReactionContent reaction) { + final String path = String.format(ISSUES_REACTION_TEMPLATE, owner, repo, issueNumber); + final String requestBody = + github.json().toJsonUnchecked(ImmutableMap.of("content", reaction.toString())); + return github.post(path, requestBody, CommentReaction.class); + } + + /** + * Deletes a reaction on an issue. See Delete + * an issue reaction + * + * @param issueNumber the issue number + * @param reactionId the reaction id + * @return a CompletableFuture containing the HTTP response + */ + public CompletableFuture deleteIssueReaction( + final long issueNumber, final long reactionId) { + final String path = + String.format(ISSUES_REACTION_ID_TEMPLATE, owner, repo, issueNumber, reactionId); + return github.delete(path); + } } diff --git a/src/main/java/com/spotify/github/v3/clients/NoopTracer.java b/src/main/java/com/spotify/github/v3/clients/NoopTracer.java deleted file mode 100644 index 5b3c769e..00000000 --- a/src/main/java/com/spotify/github/v3/clients/NoopTracer.java +++ /dev/null @@ -1,57 +0,0 @@ -/*- - * -\-\- - * github-api - * -- - * Copyright (C) 2021 Spotify AB - * -- - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * -/-/- - */ - -package com.spotify.github.v3.clients; -import com.spotify.github.Span; -import com.spotify.github.Tracer; - -import java.util.concurrent.CompletionStage; - -public class NoopTracer implements Tracer { - - public static final NoopTracer INSTANCE = new NoopTracer(); - private static final Span SPAN = - new Span() { - @Override - public Span success() { - return this; - } - - @Override - public Span failure(final Throwable t) { - return this; - } - - @Override - public void close() {} - }; - - private NoopTracer() {} - - @Override - public Span span( - final String path, - final String method, - final CompletionStage future) { - return SPAN; - } - -} - diff --git a/src/main/java/com/spotify/github/v3/clients/PullRequestClient.java b/src/main/java/com/spotify/github/v3/clients/PullRequestClient.java index 1053ec78..36d2783e 100644 --- a/src/main/java/com/spotify/github/v3/clients/PullRequestClient.java +++ b/src/main/java/com/spotify/github/v3/clients/PullRequestClient.java @@ -22,19 +22,32 @@ import static com.spotify.github.v3.clients.GitHubClient.IGNORE_RESPONSE_CONSUMER; import static com.spotify.github.v3.clients.GitHubClient.LIST_COMMIT_TYPE_REFERENCE; +import static com.spotify.github.v3.clients.GitHubClient.LIST_FILE_ITEMS; +import static com.spotify.github.v3.clients.GitHubClient.LIST_PR_COMMENT_TYPE_REFERENCE; import static com.spotify.github.v3.clients.GitHubClient.LIST_PR_TYPE_REFERENCE; import static com.spotify.github.v3.clients.GitHubClient.LIST_REVIEW_REQUEST_TYPE_REFERENCE; import static com.spotify.github.v3.clients.GitHubClient.LIST_REVIEW_TYPE_REFERENCE; +import static java.lang.Math.toIntExact; import static java.util.Objects.isNull; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.spotify.github.async.AsyncPage; -import com.spotify.github.v3.prs.*; +import com.spotify.github.jackson.Json; +import com.spotify.github.v3.git.FileItem; +import com.spotify.github.v3.prs.Comment; +import com.spotify.github.v3.prs.MergeParameters; +import com.spotify.github.v3.prs.PullRequest; +import com.spotify.github.v3.prs.PullRequestItem; +import com.spotify.github.v3.prs.RequestReviewParameters; +import com.spotify.github.v3.prs.Review; +import com.spotify.github.v3.prs.ReviewParameters; +import com.spotify.github.v3.prs.ReviewRequests; import com.spotify.github.v3.prs.requests.PullRequestCreate; import com.spotify.github.v3.prs.requests.PullRequestParameters; import com.spotify.github.v3.prs.requests.PullRequestUpdate; import com.spotify.github.v3.repos.CommitItem; +import java.io.InputStreamReader; import java.io.Reader; import java.lang.invoke.MethodHandles; import java.util.Iterator; @@ -53,7 +66,14 @@ public class PullRequestClient { private static final String PR_NUMBER_TEMPLATE = "/repos/%s/%s/pulls/%s"; private static final String PR_COMMITS_TEMPLATE = "/repos/%s/%s/pulls/%s/commits"; private static final String PR_REVIEWS_TEMPLATE = "/repos/%s/%s/pulls/%s/reviews"; - private static final String PR_REVIEW_REQUESTS_TEMPLATE = "/repos/%s/%s/pulls/%s/requested_reviewers"; + private static final String PR_REVIEW_COMMENTS_TEMPLATE = + "/repos/%s/%s/pulls/%s/reviews/%s/comments"; + private static final String PR_COMMENTS_TEMPLATE = "/repos/%s/%s/pulls/%s/comments"; + private static final String PR_CHANGED_FILES_TEMPLATE = "/repos/%s/%s/pulls/%s/files"; + private static final String PR_REVIEW_REQUESTS_TEMPLATE = + "/repos/%s/%s/pulls/%s/requested_reviewers"; + private static final String PR_COMMENT_REPLIES_TEMPLATE = + "/repos/%s/%s/pulls/%s/comments/%s/replies"; private final GitHubClient github; private final String owner; @@ -94,11 +114,23 @@ public CompletableFuture> list(final PullRequestParameters /** * Get a specific pull request. * - * @param number pull request number + * @deprecated Use {@link #get(long)} instead + * @param prNumber pull request number * @return pull request */ - public CompletableFuture get(final int number) { - final String path = String.format(PR_NUMBER_TEMPLATE, owner, repo, number); + @Deprecated + public CompletableFuture get(final int prNumber) { + return get((long) prNumber); + } + + /** + * Get a specific pull request. + * + * @param prNumber pull request number + * @return pull request + */ + public CompletableFuture get(final long prNumber) { + final String path = String.format(PR_NUMBER_TEMPLATE, owner, repo, prNumber); log.debug("Fetching pull request from " + path); return github.request(path, PullRequest.class); } @@ -117,62 +149,141 @@ public CompletableFuture create(final PullRequestCreate request) { /** * Update given pull request. * - * @param number pull request number + * @deprecated Use {@link #update(long, PullRequestUpdate)} instead + * @param prNumber pull request number + * @param request update request + * @return pull request + */ + @Deprecated + public CompletableFuture update( + final int prNumber, final PullRequestUpdate request) { + return update((long) prNumber, request); + } + + /** + * Update given pull request. + * + * @param prNumber pull request number * @param request update request * @return pull request */ - public CompletableFuture update(final int number, final PullRequestUpdate request) { - final String path = String.format(PR_NUMBER_TEMPLATE, owner, repo, number); + public CompletableFuture update( + final long prNumber, final PullRequestUpdate request) { + final String path = String.format(PR_NUMBER_TEMPLATE, owner, repo, prNumber); return github.patch(path, github.json().toJsonUnchecked(request), PullRequest.class); } /** * List pull request commits. * - * @param number pull request number + * @deprecated Use {@link #listCommits(long)} instead + * @param prNumber pull request number * @return commits */ - public CompletableFuture> listCommits(final int number) { - final String path = String.format(PR_COMMITS_TEMPLATE, owner, repo, number); + @Deprecated + public CompletableFuture> listCommits(final int prNumber) { + return listCommits((long) prNumber); + } + + /** + * List pull request commits. + * + * @param prNumber pull request number + * @return commits + */ + public CompletableFuture> listCommits(final long prNumber) { + final String path = String.format(PR_COMMITS_TEMPLATE, owner, repo, prNumber); log.debug("Fetching pull request commits from " + path); - return github.request(path, LIST_COMMIT_TYPE_REFERENCE); + return github + .request(path) + .thenApply( + response -> + Json.create() + .fromJsonUncheckedNotNull(response.bodyString(), LIST_COMMIT_TYPE_REFERENCE)); + } + + public Iterator> listCommits(final long prNumber, final int itemsPerPage) { + final String path = String.format(PR_COMMITS_TEMPLATE, owner, repo, prNumber); + + return new GithubPageIterator<>( + new GithubPage<>(github, path, LIST_COMMIT_TYPE_REFERENCE, itemsPerPage)); } /** * List pull request reviews. Reviews are returned in chronological order. * - * @param number pull request number + * @deprecated Use {@link #listReviews(long)} instead + * @param prNumber pull request number * @return list of reviews */ - public CompletableFuture> listReviews(final int number) { - final String path = String.format(PR_REVIEWS_TEMPLATE, owner, repo, number); - log.debug("Fetching pull request reviews from " + path); - return github.request(path, LIST_REVIEW_TYPE_REFERENCE); + @Deprecated + public CompletableFuture> listReviews(final int prNumber) { + return listReviews((long) prNumber); + } + + /** + * List pull request reviews. Reviews are returned in chronological order. + * + * @param prNumber pull request number + * @return list of reviews + */ + public CompletableFuture> listReviews(final long prNumber) { + final String path = String.format(PR_REVIEWS_TEMPLATE, owner, repo, prNumber); + log.debug("Fetching pull request reviews from " + path); + return github.request(path, LIST_REVIEW_TYPE_REFERENCE); } /** * List pull request reviews paginated. Reviews are returned in chronological order. * - * @param number pull request number - * @param itemsPerPage number of items per page + * @deprecated Use {@link #listReviews(long,long)} instead + * @param prNumber pull request number + * @param itemsPerPage prNumber of items per page * @return iterator of reviews */ - public Iterator> listReviews(final int number, final int itemsPerPage) { - // FIXME Use itemsPerPage property - final String path = String.format(PR_REVIEWS_TEMPLATE, owner, repo, number); + @Deprecated + public Iterator> listReviews(final int prNumber, final int itemsPerPage) { + return listReviews((long) prNumber, itemsPerPage); + } + + /** + * List pull request reviews paginated. Reviews are returned in chronological order. + * + * @param prNumber pull request number + * @param itemsPerPage prNumber of items per page + * @return iterator of reviews + */ + public Iterator> listReviews(final long prNumber, final long itemsPerPage) { + final String path = String.format(PR_REVIEWS_TEMPLATE, owner, repo, prNumber); log.debug("Fetching pull request reviews from " + path); - return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_REVIEW_TYPE_REFERENCE)); + return new GithubPageIterator<>( + new GithubPage<>(github, path, LIST_REVIEW_TYPE_REFERENCE, toIntExact(itemsPerPage))); } /** * Creates a review for a pull request. * - * @param number pull request number + * @deprecated Use {@link #createReview(long,ReviewParameters)} instead + * @param prNumber pull request number * @param properties properties for reviewing the PR, such as sha, body and event * @see "https://developer.github.com/v3/pulls/reviews/#create-a-review-for-a-pull-request" */ - public CompletableFuture createReview(final int number, final ReviewParameters properties) { - final String path = String.format(PR_REVIEWS_TEMPLATE, owner, repo, number); + @Deprecated + public CompletableFuture createReview( + final int prNumber, final ReviewParameters properties) { + return createReview((long) prNumber, properties); + } + + /** + * Creates a review for a pull request. + * + * @param prNumber pull request number + * @param properties properties for reviewing the PR, such as sha, body and event + * @see "https://developer.github.com/v3/pulls/reviews/#create-a-review-for-a-pull-request" + */ + public CompletableFuture createReview( + final long prNumber, final ReviewParameters properties) { + final String path = String.format(PR_REVIEWS_TEMPLATE, owner, repo, prNumber); final String jsonPayload = github.json().toJsonUnchecked(properties); log.debug("Creating review for PR: " + path); return github.post(path, jsonPayload, Review.class); @@ -181,11 +292,23 @@ public CompletableFuture createReview(final int number, final ReviewPara /** * List pull request requested reviews. * - * @param number pull request number + * @deprecated Use {@link #listReviewRequests(long)} instead + * @param prNumber pull request number + * @return list of reviews + */ + @Deprecated + public CompletableFuture listReviewRequests(final int prNumber) { + return listReviewRequests((long) prNumber); + } + + /** + * List pull request requested reviews. + * + * @param prNumber pull request number * @return list of reviews */ - public CompletableFuture listReviewRequests(final int number) { - final String path = String.format(PR_REVIEW_REQUESTS_TEMPLATE, owner, repo, number); + public CompletableFuture listReviewRequests(final long prNumber) { + final String path = String.format(PR_REVIEW_REQUESTS_TEMPLATE, owner, repo, prNumber); log.debug("Fetching pull request requested reviews from " + path); return github.request(path, LIST_REVIEW_REQUEST_TYPE_REFERENCE); } @@ -193,12 +316,27 @@ public CompletableFuture listReviewRequests(final int number) { /** * Requests a review for a pull request. * - * @param number pull request number + * @deprecated Use {@link #requestReview(long,RequestReviewParameters)} instead + * @param prNumber pull request number + * @param properties properties for reviewing the PR, such as reviewers and team_reviewers. + * @see "https://docs.github.com/en/rest/reference/pulls#request-reviewers-for-a-pull-request" + */ + @Deprecated + public CompletableFuture requestReview( + final int prNumber, final RequestReviewParameters properties) { + return requestReview((long) prNumber, properties); + } + + /** + * Requests a review for a pull request. + * + * @param prNumber pull request number * @param properties properties for reviewing the PR, such as reviewers and team_reviewers. * @see "https://docs.github.com/en/rest/reference/pulls#request-reviewers-for-a-pull-request" */ - public CompletableFuture requestReview(final int number, final RequestReviewParameters properties) { - final String path = String.format(PR_REVIEW_REQUESTS_TEMPLATE, owner, repo, number); + public CompletableFuture requestReview( + final long prNumber, final RequestReviewParameters properties) { + final String path = String.format(PR_REVIEW_REQUESTS_TEMPLATE, owner, repo, prNumber); final String jsonPayload = github.json().toJsonUnchecked(properties); log.debug("Requesting reviews for PR: " + path); return github.post(path, jsonPayload, PullRequest.class); @@ -207,12 +345,27 @@ public CompletableFuture requestReview(final int number, final Requ /** * Remove a request for review for a pull request. * - * @param number pull request number + * @deprecated Use {@link #removeRequestedReview(long,RequestReviewParameters)} instead + * @param prNumber pull request number * @param properties properties for reviewing the PR, such as reviewers and team_reviewers. * @see "https://docs.github.com/en/rest/reference/pulls#request-reviewers-for-a-pull-request" */ - public CompletableFuture removeRequestedReview(final int number, final RequestReviewParameters properties) { - final String path = String.format(PR_REVIEW_REQUESTS_TEMPLATE, owner, repo, number); + @Deprecated + public CompletableFuture removeRequestedReview( + final int prNumber, final RequestReviewParameters properties) { + return removeRequestedReview((long) prNumber, properties); + } + + /** + * Remove a request for review for a pull request. + * + * @param prNumber pull request number + * @param properties properties for reviewing the PR, such as reviewers and team_reviewers. + * @see "https://docs.github.com/en/rest/reference/pulls#request-reviewers-for-a-pull-request" + */ + public CompletableFuture removeRequestedReview( + final long prNumber, final RequestReviewParameters properties) { + final String path = String.format(PR_REVIEW_REQUESTS_TEMPLATE, owner, repo, prNumber); final String jsonPayload = github.json().toJsonUnchecked(properties); log.debug("Removing requested reviews for PR: " + path); return github.delete(path, jsonPayload).thenAccept(IGNORE_RESPONSE_CONSUMER); @@ -221,52 +374,157 @@ public CompletableFuture removeRequestedReview(final int number, final Req /** * Merges a pull request. * - * @param number pull request number + * @deprecated Use {@link #merge(long,MergeParameters)} instead + * @param prNumber pull request number + * @param properties the properties on merging the PR, such as title, message and sha + * @see "https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button" + */ + @Deprecated + public CompletableFuture merge(final int prNumber, final MergeParameters properties) { + return merge((long) prNumber, properties); + } + + /** + * Merges a pull request. + * + * @param prNumber pull request number * @param properties the properties on merging the PR, such as title, message and sha * @see "https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button" */ - public CompletableFuture merge(final int number, final MergeParameters properties) { - final String path = String.format(PR_NUMBER_TEMPLATE + "/merge", owner, repo, number); + public CompletableFuture merge(final long prNumber, final MergeParameters properties) { + final String path = String.format(PR_NUMBER_TEMPLATE + "/merge", owner, repo, prNumber); final String jsonPayload = github.json().toJsonUnchecked(properties); log.debug("Merging pr, running: {}", path); return github.put(path, jsonPayload).thenAccept(IGNORE_RESPONSE_CONSUMER); } - public CompletableFuture patch(final int number) { - final String path = String.format(PR_NUMBER_TEMPLATE, owner, repo, number); - final Map extraHeaders = ImmutableMap.of( - HttpHeaders.ACCEPT, "application/vnd.github.patch" - ); + /** + * Fetches a pull request patch. + * + * @deprecated Use {@link #patch(long)} instead + * @param prNumber pull request number + * @return reader for the patch + */ + @Deprecated + public CompletableFuture patch(final int prNumber) { + return patch((long) prNumber); + } + + /** + * Fetches a pull request patch. + * + * @param prNumber pull request number + * @return reader for the patch + */ + public CompletableFuture patch(final long prNumber) { + final String path = String.format(PR_NUMBER_TEMPLATE, owner, repo, prNumber); + final Map extraHeaders = + ImmutableMap.of(HttpHeaders.ACCEPT, "application/vnd.github.patch"); log.debug("Fetching pull request patch from " + path); - return github.request(path, extraHeaders) - .thenApply(response -> { - final var body = response.body(); - if (isNull(body)) { - return Reader.nullReader(); - } - return body.charStream(); - }); - } - - public CompletableFuture diff(final int number) { - final String path = String.format(PR_NUMBER_TEMPLATE, owner, repo, number); - final Map extraHeaders = ImmutableMap.of( - HttpHeaders.ACCEPT, "application/vnd.github.diff" - ); + return github + .request(path, extraHeaders) + .thenApply( + response -> { + final var body = response.body(); + if (isNull(body)) { + return Reader.nullReader(); + } + return new InputStreamReader(body); + }); + } + + /** + * Fetches a pull request diff. + * + * @deprecated Use {@link #diff(long)} instead + * @param prNumber pull request number + * @return reader for the diff + */ + @Deprecated + public CompletableFuture diff(final int prNumber) { + return diff((long) prNumber); + } + + /** + * Fetches a pull request diff. + * + * @param prNumber pull request number + * @return reader for the diff + */ + public CompletableFuture diff(final long prNumber) { + final String path = String.format(PR_NUMBER_TEMPLATE, owner, repo, prNumber); + final Map extraHeaders = + ImmutableMap.of(HttpHeaders.ACCEPT, "application/vnd.github.diff"); log.debug("Fetching pull diff from " + path); - return github.request(path, extraHeaders) - .thenApply(response -> { - final var body = response.body(); - if (isNull(body)) { - return Reader.nullReader(); - } - return body.charStream(); - }); + return github + .request(path, extraHeaders) + .thenApply( + response -> { + final var body = response.body(); + if (isNull(body)) { + return Reader.nullReader(); + } + return new InputStreamReader(body); + }); } + public Iterator> changedFiles(final long prNumber) { + final String path = String.format(PR_CHANGED_FILES_TEMPLATE, owner, repo, prNumber); + return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_FILE_ITEMS)); + } + + /** + * List pull requests using given parameters. + * + * @param parameterPath request parameters + * @return pull requests + */ private CompletableFuture> list(final String parameterPath) { final String path = String.format(PR_TEMPLATE + parameterPath, owner, repo); log.debug("Fetching pull requests from " + path); return github.request(path, LIST_PR_TYPE_REFERENCE); } + + /** + * List pull request review comments. + * + * @param prNumber pull request number + * @return iterator of comments + */ + public Iterator> listComments(final long prNumber) { + final String path = String.format(PR_COMMENTS_TEMPLATE, owner, repo, prNumber); + return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_PR_COMMENT_TYPE_REFERENCE)); + } + + /** + * Creates a reply to a pull request review comment. + * + * @param prNumber pull request number + * @param commentId the ID of the comment to reply to + * @param body the reply message + * @return the created comment + * @see "https://docs.github.com/en/rest/pulls/comments#create-a-reply-for-a-review-comment" + */ + public CompletableFuture createCommentReply( + final long prNumber, final long commentId, final String body) { + final String path = + String.format(PR_COMMENT_REPLIES_TEMPLATE, owner, repo, prNumber, commentId); + final Map payload = ImmutableMap.of("body", body); + final String jsonPayload = github.json().toJsonUnchecked(payload); + log.debug("Creating reply to PR comment: " + path); + return github.post(path, jsonPayload, Comment.class); + } + + /** + * List pull request review comments for a specific review with pagination. + * + * @param prNumber pull request number + * @param reviewId the ID of the review + * @return iterator of comments for the review + * @see "https://docs.github.com/en/rest/pulls/comments#list-comments-for-a-pull-request-review" + */ + public Iterator> listReviewComments(final long prNumber, final long reviewId) { + final String path = String.format(PR_REVIEW_COMMENTS_TEMPLATE, owner, repo, prNumber, reviewId); + return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_PR_COMMENT_TYPE_REFERENCE)); + } } diff --git a/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java b/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java index c2c49c04..a80e46e1 100644 --- a/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java +++ b/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java @@ -150,6 +150,15 @@ public ChecksClient createChecksApiClient() { return new ChecksClient(github, owner, repo); } + /** + * Actions API client + * + * @return Actions API client + */ + public ActionsClient createActionsClient() { + return ActionsClient.create(github, owner, repo); + } + /** * Get information about this repository. * @@ -205,7 +214,7 @@ public Iterator> listAuthenticatedUserRepositories( */ public CompletableFuture isCollaborator(final String user) { final String path = String.format(REPOSITORY_COLLABORATOR, owner, repo, user); - return github.request(path).thenApply(response -> response.code() == NO_CONTENT); + return github.request(path).thenApply(response -> response.statusCode() == NO_CONTENT); } /** @@ -226,7 +235,7 @@ public CompletableFuture> addCollaborator( response -> { // Non-successful statuses result in an RequestNotOkException exception and this code // not called. - if (response.code() == NO_CONTENT) { + if (response.statusCode() == NO_CONTENT) { /* GitHub returns a 204 when: - an existing collaborator is added as a collaborator @@ -239,8 +248,7 @@ public CompletableFuture> addCollaborator( final RepositoryInvitation invitation = github .json() - .fromJsonUnchecked( - GitHubClient.responseBodyUnchecked(response), RepositoryInvitation.class); + .fromJsonUnchecked(response.bodyString(), RepositoryInvitation.class); return Optional.of(invitation); }); } @@ -300,18 +308,7 @@ private CompletableFuture> downloadRepository( final String path, final Optional maybeRef) { final var repoRef = maybeRef.orElse(""); final var repoPath = String.format(path, owner, repo, repoRef); - return github - .request(repoPath) - .thenApply( - response -> { - var body = response.body(); - - if (body == null) { - return Optional.empty(); - } - - return Optional.of(body.byteStream()); - }); + return github.request(repoPath).thenApply(response -> Optional.ofNullable(response.body())); } /** @@ -654,15 +651,12 @@ public CompletableFuture> merge( // Non-successful statuses result in an RequestNotOkException exception and this code // not being called. - if (response.code() == NO_CONTENT) { + if (response.statusCode() == NO_CONTENT) { // Base already contains the head, nothing to merge return Optional.empty(); } final CommitItem commitItem = - github - .json() - .fromJsonUnchecked( - GitHubClient.responseBodyUnchecked(response), CommitItem.class); + github.json().fromJsonUnchecked(response.bodyString(), CommitItem.class); return Optional.of(commitItem); }); } @@ -685,10 +679,7 @@ public CompletableFuture createFork(final String organization) { .thenApply( response -> { final Repository repositoryItem = - github - .json() - .fromJsonUnchecked( - GitHubClient.responseBodyUnchecked(response), Repository.class); + github.json().fromJsonUnchecked(response.bodyString(), Repository.class); return repositoryItem; }); } @@ -705,11 +696,11 @@ private String getContentPath(final String path, final String query) { * * @param request The repository dispatch request. */ - - public CompletableFuture createRepositoryDispatchEvent(final RepositoryDispatch request) { + public CompletableFuture createRepositoryDispatchEvent( + final RepositoryDispatch request) { final String path = String.format(CREATE_REPOSITORY_DISPATCH_EVENT_TEMPLATE, owner, repo); return github .post(path, github.json().toJsonUnchecked(request)) - .thenApply(response -> response.code() == NO_CONTENT); //should always return a 204 + .thenApply(response -> response.statusCode() == NO_CONTENT); // should always return a 204 } } diff --git a/src/main/java/com/spotify/github/v3/clients/TeamClient.java b/src/main/java/com/spotify/github/v3/clients/TeamClient.java index 630c86de..409d5911 100644 --- a/src/main/java/com/spotify/github/v3/clients/TeamClient.java +++ b/src/main/java/com/spotify/github/v3/clients/TeamClient.java @@ -18,7 +18,6 @@ * -/-/- */ - package com.spotify.github.v3.clients; import static com.spotify.github.v3.clients.GitHubClient.*; @@ -28,8 +27,10 @@ import com.spotify.github.v3.User; import com.spotify.github.v3.orgs.Membership; import com.spotify.github.v3.orgs.TeamInvitation; +import com.spotify.github.v3.orgs.requests.ImmutableTeamRepoPermissionUpdate; import com.spotify.github.v3.orgs.requests.MembershipCreate; import com.spotify.github.v3.orgs.requests.TeamCreate; +import com.spotify.github.v3.orgs.requests.TeamRepoPermissionUpdate; import com.spotify.github.v3.orgs.requests.TeamUpdate; import java.lang.invoke.MethodHandles; import java.util.Iterator; @@ -48,12 +49,14 @@ public class TeamClient { private static final String MEMBERS_TEMPLATE = "/orgs/%s/teams/%s/members"; - private static final String PAGED_MEMBERS_TEMPLATE = "/orgs/%s/teams/%s/members?per_page=%d"; + private static final String PAGED_MEMBERS_TEMPLATE = "/orgs/%s/teams/%s/members"; private static final String MEMBERSHIP_TEMPLATE = "/orgs/%s/teams/%s/memberships/%s"; private static final String INVITATIONS_TEMPLATE = "/orgs/%s/teams/%s/invitations"; + private static final String REPO_TEMPLATE = "/orgs/%s/teams/%s/repos/%s/%s"; + private final GitHubClient github; private final String org; @@ -75,7 +78,7 @@ static TeamClient create(final GitHubClient github, final String org) { */ public CompletableFuture createTeam(final TeamCreate request) { final String path = String.format(TEAM_TEMPLATE, org); - log.debug("Creating team in: " + path); + log.debug("Creating team in: {}", path); return github.post(path, github.json().toJsonUnchecked(request), Team.class); } @@ -87,7 +90,7 @@ public CompletableFuture createTeam(final TeamCreate request) { */ public CompletableFuture getTeam(final String slug) { final String path = String.format(TEAM_SLUG_TEMPLATE, org, slug); - log.debug("Fetching team from " + path); + log.debug("Fetching team from {}", path); return github.request(path, Team.class); } @@ -98,7 +101,7 @@ public CompletableFuture getTeam(final String slug) { */ public CompletableFuture> listTeams() { final String path = String.format(TEAM_TEMPLATE, org); - log.debug("Fetching teams from " + path); + log.debug("Fetching teams from {}", path); return github.request(path, LIST_TEAMS); } @@ -111,7 +114,7 @@ public CompletableFuture> listTeams() { */ public CompletableFuture updateTeam(final TeamUpdate request, final String slug) { final String path = String.format(TEAM_SLUG_TEMPLATE, org, slug); - log.debug("Updating team in: " + path); + log.debug("Updating team in: {}", path); return github.patch(path, github.json().toJsonUnchecked(request), Team.class); } @@ -123,7 +126,7 @@ public CompletableFuture updateTeam(final TeamUpdate request, final String */ public CompletableFuture deleteTeam(final String slug) { final String path = String.format(TEAM_SLUG_TEMPLATE, org, slug); - log.debug("Deleting team from: " + path); + log.debug("Deleting team from: {}", path); return github.delete(path).thenAccept(IGNORE_RESPONSE_CONSUMER); } @@ -133,9 +136,10 @@ public CompletableFuture deleteTeam(final String slug) { * @param request update membership request * @return membership */ - public CompletableFuture updateMembership(final MembershipCreate request, final String slug, final String username) { + public CompletableFuture updateMembership( + final MembershipCreate request, final String slug, final String username) { final String path = String.format(MEMBERSHIP_TEMPLATE, org, slug, username); - log.debug("Updating membership in: " + path); + log.debug("Updating membership in: {}", path); return github.put(path, github.json().toJsonUnchecked(request), Membership.class); } @@ -148,7 +152,7 @@ public CompletableFuture updateMembership(final MembershipCreate req */ public CompletableFuture getMembership(final String slug, final String username) { final String path = String.format(MEMBERSHIP_TEMPLATE, org, slug, username); - log.debug("Fetching membership for: " + path); + log.debug("Fetching membership for: {}", path); return github.request(path, Membership.class); } @@ -160,7 +164,7 @@ public CompletableFuture getMembership(final String slug, final Stri */ public CompletableFuture> listTeamMembers(final String slug) { final String path = String.format(MEMBERS_TEMPLATE, org, slug); - log.debug("Fetching members for: " + path); + log.debug("Fetching members for: {}", path); return github.request(path, LIST_TEAM_MEMBERS); } @@ -172,9 +176,9 @@ public CompletableFuture> listTeamMembers(final String slug) { * @return list of all users in a team */ public Iterator> listTeamMembers(final String slug, final int pageSize) { - final String path = String.format(PAGED_MEMBERS_TEMPLATE, org, slug, pageSize); - log.debug("Fetching members for: " + path); - return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_TEAM_MEMBERS)); + final String path = String.format(PAGED_MEMBERS_TEMPLATE, org, slug); + log.debug("Fetching members for: {}", path); + return new GithubPageIterator<>(new GithubPage<>(github, path, LIST_TEAM_MEMBERS, pageSize)); } /** @@ -185,7 +189,7 @@ public Iterator> listTeamMembers(final String slug, final int pa */ public CompletableFuture deleteMembership(final String slug, final String username) { final String path = String.format(MEMBERSHIP_TEMPLATE, org, slug, username); - log.debug("Deleting membership from: " + path); + log.debug("Deleting membership from: {}", path); return github.delete(path).thenAccept(IGNORE_RESPONSE_CONSUMER); } @@ -197,7 +201,31 @@ public CompletableFuture deleteMembership(final String slug, final String */ public CompletableFuture> listPendingTeamInvitations(final String slug) { final String path = String.format(INVITATIONS_TEMPLATE, org, slug); - log.debug("Fetching pending invitations for: " + path); + log.debug("Fetching pending invitations for: {}", path); return github.request(path, LIST_PENDING_TEAM_INVITATIONS); } + + /** + * Update permissions for a team on a specific repository. + * + * @param slug the team slug + * @param repo the repository name + * @param permission the permission level (pull, push, maintain, triage, admin, or a custom repo defined role name) + * @return void status code 204 if successful + */ + public CompletableFuture updateTeamPermissions( + final String slug, final String repo, final String permission) { + final String path = String.format(REPO_TEMPLATE, org, slug, org, repo); + final TeamRepoPermissionUpdate request = + ImmutableTeamRepoPermissionUpdate.builder() + .org(org) + .repo(repo) + .teamSlug(slug) + .permission(permission) + .build(); + log.debug("Updating team permissions for: {}", path); + return github + .put(path, github.json().toJsonUnchecked(request)) + .thenAccept(IGNORE_RESPONSE_CONSUMER); + } } diff --git a/src/main/java/com/spotify/github/v3/clients/UserClient.java b/src/main/java/com/spotify/github/v3/clients/UserClient.java index 0d48e027..6fec500d 100644 --- a/src/main/java/com/spotify/github/v3/clients/UserClient.java +++ b/src/main/java/com/spotify/github/v3/clients/UserClient.java @@ -55,7 +55,7 @@ public CompletableFuture suspendUser( final String path = String.format(SUSPEND_USER_TEMPLATE, username); return github .put(path, github.json().toJsonUnchecked(reason)) - .thenApply(resp -> resp.code() == NO_CONTENT); + .thenApply(resp -> resp.statusCode() == NO_CONTENT); } /** @@ -69,6 +69,6 @@ public CompletableFuture unSuspendUser( final String path = String.format(SUSPEND_USER_TEMPLATE, username); return github .delete(path, github.json().toJsonUnchecked(reason)) - .thenApply(resp -> resp.code() == NO_CONTENT); + .thenApply(resp -> resp.statusCode() == NO_CONTENT); } } diff --git a/src/main/java/com/spotify/github/v3/clients/WorkflowsClient.java b/src/main/java/com/spotify/github/v3/clients/WorkflowsClient.java new file mode 100644 index 00000000..8aeb6fa5 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/clients/WorkflowsClient.java @@ -0,0 +1,73 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.clients; + +import com.google.common.collect.ImmutableMap; +import com.spotify.github.v3.workflows.WorkflowsRepositoryResponseList; +import com.spotify.github.v3.workflows.WorkflowsResponse; + +import javax.ws.rs.core.HttpHeaders; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +/** Workflows API client */ +public class WorkflowsClient { + private static final String LIST_REPOSITORY_WORKFLOWS_URI = "/repos/%s/%s/actions/workflows"; + private static final String GET_WORKFLOW_URI = "/repos/%s/%s/actions/workflows/%s"; + + private final GitHubClient github; + private final String owner; + private final String repo; + + private final Map extraHeaders = + ImmutableMap.of(HttpHeaders.ACCEPT, "application/vnd.github+json"); + + public WorkflowsClient(final GitHubClient github, final String owner, final String repo) { + this.github = github; + this.owner = owner; + this.repo = repo; + } + + static WorkflowsClient create(final GitHubClient github, final String owner, final String repo) { + return new WorkflowsClient(github, owner, repo); + } + + /** + * List workflows for a repository. + * + * @return a list of workflows for the repository + */ + public CompletableFuture listWorkflows() { + final String path = String.format(LIST_REPOSITORY_WORKFLOWS_URI, owner, repo); + return github.request(path, WorkflowsRepositoryResponseList.class, extraHeaders); + } + + /** + * Gets a workflow by id. + * + * @param id the workflow id + * @return a WorkflowsResponse + */ + public CompletableFuture getWorkflow(final int id) { + final String path = String.format(GET_WORKFLOW_URI, owner, repo, id); + return github.request(path, WorkflowsResponse.class, extraHeaders); + } +} diff --git a/src/main/java/com/spotify/github/v3/comment/Comment.java b/src/main/java/com/spotify/github/v3/comment/Comment.java index 175fdc19..9621255f 100644 --- a/src/main/java/com/spotify/github/v3/comment/Comment.java +++ b/src/main/java/com/spotify/github/v3/comment/Comment.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -46,7 +46,7 @@ public interface Comment extends UpdateTracking { URI htmlUrl(); /** Comment ID. */ - int id(); + Long id(); /** The {@link User} that made the comment. */ @Nullable @@ -60,6 +60,7 @@ public interface Comment extends UpdateTracking { * * @deprecated Use {@link #position()} instead */ + @Deprecated Optional line(); /** Relative path of the file to comment on. */ @@ -74,4 +75,8 @@ public interface Comment extends UpdateTracking { /** The issueURL which the comment belongs to. */ Optional issueUrl(); + + /** Node ID */ + @Nullable + String nodeId(); } diff --git a/src/main/java/com/spotify/github/v3/comment/CommentReaction.java b/src/main/java/com/spotify/github/v3/comment/CommentReaction.java new file mode 100644 index 00000000..705d0dd2 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/comment/CommentReaction.java @@ -0,0 +1,50 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ +package com.spotify.github.v3.comment; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.GithubStyle; +import com.spotify.github.UpdateTracking; +import com.spotify.github.v3.User; +import org.immutables.value.Value; + +/** + * Comment reaction object. + * + *

See About + * GitHub Issue Comment reactions + */ +@Value.Immutable +@GithubStyle +@JsonSerialize(as = ImmutableCommentReaction.class) +@JsonDeserialize(as = ImmutableCommentReaction.class) +public interface CommentReaction extends UpdateTracking { + + /** Reaction ID. */ + long id(); + + /** Reaction user. */ + User user(); + + /** Reaction content. */ + CommentReactionContent content(); +} diff --git a/src/main/java/com/spotify/github/v3/comment/CommentReactionContent.java b/src/main/java/com/spotify/github/v3/comment/CommentReactionContent.java new file mode 100644 index 00000000..cc4f8727 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/comment/CommentReactionContent.java @@ -0,0 +1,56 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ +package com.spotify.github.v3.comment; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.jackson.CommentReactionContentDeserializer; +import com.spotify.github.jackson.CommentReactionContentSerializer; + +/** + * Comment reaction content. + * + *

See About + * GitHub Issue Comment reactions + */ +@JsonDeserialize(using = CommentReactionContentDeserializer.class) +@JsonSerialize(using = CommentReactionContentSerializer.class) +public enum CommentReactionContent { + THUMBS_UP("+1"), // 👍 + THUMBS_DOWN("-1"), // 👎 + LAUGH("laugh"), // 😄 + HOORAY("hooray"), // 🎉 + CONFUSED("confused"), // 😕 + HEART("heart"), // ❤️ + ROCKET("rocket"), // 🚀 + EYES("eyes"); // 👀 + + private final String reaction; + + CommentReactionContent(final String reaction) { + this.reaction = reaction; + } + + @Override + public String toString() { + return reaction; + } +} diff --git a/src/main/java/com/spotify/github/v3/exceptions/GithubException.java b/src/main/java/com/spotify/github/v3/exceptions/GithubException.java index 7599c719..b88f809f 100644 --- a/src/main/java/com/spotify/github/v3/exceptions/GithubException.java +++ b/src/main/java/com/spotify/github/v3/exceptions/GithubException.java @@ -22,6 +22,8 @@ /** Common github exception */ public class GithubException extends RuntimeException { + private static final long serialVersionUID = 1L; + /** * C'tor for setting a message diff --git a/src/main/java/com/spotify/github/v3/exceptions/ReadOnlyRepositoryException.java b/src/main/java/com/spotify/github/v3/exceptions/ReadOnlyRepositoryException.java index f20a691e..08dc681b 100644 --- a/src/main/java/com/spotify/github/v3/exceptions/ReadOnlyRepositoryException.java +++ b/src/main/java/com/spotify/github/v3/exceptions/ReadOnlyRepositoryException.java @@ -25,6 +25,8 @@ /** The Read only repository exception. */ public class ReadOnlyRepositoryException extends RequestNotOkException { + private static final long serialVersionUID = 1L; + /** * Instantiates a new Read only repository exception. * diff --git a/src/main/java/com/spotify/github/v3/exceptions/RequestNotOkException.java b/src/main/java/com/spotify/github/v3/exceptions/RequestNotOkException.java index ef6e8815..342c00ea 100644 --- a/src/main/java/com/spotify/github/v3/exceptions/RequestNotOkException.java +++ b/src/main/java/com/spotify/github/v3/exceptions/RequestNotOkException.java @@ -39,6 +39,8 @@ /** HTTP response with non-200 StatusCode. */ public class RequestNotOkException extends GithubException { + private static final long serialVersionUID = 1L; + private final int statusCode; private final String method; diff --git a/src/main/java/com/spotify/github/v3/issues/Issue.java b/src/main/java/com/spotify/github/v3/issues/Issue.java index c1d77819..2d5c7988 100644 --- a/src/main/java/com/spotify/github/v3/issues/Issue.java +++ b/src/main/java/com/spotify/github/v3/issues/Issue.java @@ -41,18 +41,16 @@ public interface Issue extends CloseTracking { /** ID. */ @Nullable - Integer id(); + Long id(); /** URL. */ @Nullable URI url(); /** Events URL. */ - @Nullable Optional eventsUrl(); /** Repository URL. */ - @Nullable Optional repositoryUrl(); /** Labels URL template. */ @@ -69,7 +67,7 @@ public interface Issue extends CloseTracking { /** Number. */ @Nullable - Integer number(); + Long number(); /** Indicates the state of the issues to return. Can be either open, closed, or all. */ @Nullable @@ -80,7 +78,6 @@ public interface Issue extends CloseTracking { String title(); /** The contents of the issue. */ - @Nullable Optional body(); /** User. */ diff --git a/src/main/java/com/spotify/github/v3/issues/Label.java b/src/main/java/com/spotify/github/v3/issues/Label.java index bf78bad0..da46cc6f 100644 --- a/src/main/java/com/spotify/github/v3/issues/Label.java +++ b/src/main/java/com/spotify/github/v3/issues/Label.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,29 +20,57 @@ package com.spotify.github.v3.issues; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.spotify.github.GithubStyle; + import java.net.URI; import javax.annotation.Nullable; + import org.immutables.value.Value; -/** Issue label resource */ +/** + * Issue label resource + */ @Value.Immutable @GithubStyle @JsonSerialize(as = ImmutableLabel.class) @JsonDeserialize(as = ImmutableLabel.class) public interface Label { - /** URL */ - @Nullable - URI url(); + /** + * Id + */ + Long id(); + + @Nullable + String nodeId(); + + /** + * URL + */ + @Nullable + URI url(); + + /** + * Name + */ + @Nullable + String name(); + + /** + * Color + */ + @Nullable + String color(); - /** Name */ - @Nullable - String name(); + @Nullable + String description(); - /** Color */ - @Nullable - String color(); + /** + * Default + */ + @JsonProperty("default") + boolean isDefault(); } diff --git a/src/main/java/com/spotify/github/v3/orgs/requests/TeamRepoPermissionUpdate.java b/src/main/java/com/spotify/github/v3/orgs/requests/TeamRepoPermissionUpdate.java new file mode 100644 index 00000000..5263ff5f --- /dev/null +++ b/src/main/java/com/spotify/github/v3/orgs/requests/TeamRepoPermissionUpdate.java @@ -0,0 +1,38 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.orgs.requests; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.GithubStyle; +import org.immutables.value.Value; + +/** Request to update permissions of a team for a specific repo */ +@Value.Immutable +@GithubStyle +@JsonSerialize(as = ImmutableTeamRepoPermissionUpdate.class) +@JsonDeserialize(as = ImmutableTeamRepoPermissionUpdate.class) +public interface TeamRepoPermissionUpdate { + String org(); + String repo(); + String teamSlug(); + String permission(); +} diff --git a/src/main/java/com/spotify/github/v3/prs/AutoMerge.java b/src/main/java/com/spotify/github/v3/prs/AutoMerge.java new file mode 100644 index 00000000..6cbad38e --- /dev/null +++ b/src/main/java/com/spotify/github/v3/prs/AutoMerge.java @@ -0,0 +1,49 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.prs; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.GithubStyle; +import com.spotify.github.v3.User; +import org.immutables.value.Value; + +import javax.annotation.Nullable; + +@Value.Immutable +@GithubStyle +@JsonSerialize(as = ImmutableAutoMerge.class) +@JsonDeserialize(as = ImmutableAutoMerge.class) +public interface AutoMerge { + // Who enabled the auto merge + User enabledBy(); + + // Merge Method chosen for the auto merge + String mergeMethod(); + + // The commit title to use when merging the pull request + @Nullable + String commitTitle(); + + // The commit message to use when merging the pull request + @Nullable + String commitMessage(); +} diff --git a/src/main/java/com/spotify/github/v3/prs/Comment.java b/src/main/java/com/spotify/github/v3/prs/Comment.java index 0c890408..c15d3dff 100644 --- a/src/main/java/com/spotify/github/v3/prs/Comment.java +++ b/src/main/java/com/spotify/github/v3/prs/Comment.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -73,7 +73,6 @@ public interface Comment extends UpdateTracking { /** Base commit sha. */ @Nullable String originalCommitId(); - /** Comment author. */ @Nullable User user(); @@ -82,6 +81,38 @@ public interface Comment extends UpdateTracking { @Nullable String body(); + /** The ID of the comment to reply to. */ + @Nullable + Long inReplyToId(); + + /** The author association of the comment. */ + @Nullable + String authorAssociation(); + + /** The starting line number in the diff. */ + @Nullable + Integer startLine(); + + /** The starting line number in the original file. */ + @Nullable + Integer originalStartLine(); + + /** The side of the diff where the starting line is from. */ + @Nullable + String startSide(); + + /** The line number in the diff. */ + @Nullable + Integer line(); + + /** The line number in the original file. */ + @Nullable + Integer originalLine(); + + /** The side of the diff where the line is from. */ + @Nullable + String side(); + /** Comment URL. */ @Nullable URI htmlUrl(); @@ -94,4 +125,12 @@ public interface Comment extends UpdateTracking { @Nullable @JsonProperty("_links") CommentLinks links(); + + /** Node ID */ + @Nullable + String nodeId(); + + /** Pull request review ID. */ + @Nullable + Long pullRequestReviewId(); } diff --git a/src/main/java/com/spotify/github/v3/prs/PartialPullRequestItem.java b/src/main/java/com/spotify/github/v3/prs/PartialPullRequestItem.java new file mode 100644 index 00000000..9e8a1177 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/prs/PartialPullRequestItem.java @@ -0,0 +1,55 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ +package com.spotify.github.v3.prs; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.spotify.github.CloseTracking; +import com.spotify.github.GithubStyle; +import org.immutables.value.Value; + +import javax.annotation.Nullable; +import java.net.URI; + +@Value.Immutable +@GithubStyle +@JsonSerialize(as = ImmutablePartialPullRequestItem.class) +@JsonDeserialize(as = ImmutablePartialPullRequestItem.class) +public interface PartialPullRequestItem extends CloseTracking { + /** ID. */ + @Nullable + Long id(); + + /** URL. */ + @Nullable + URI url(); + + /** Number. */ + @Nullable + Long number(); + + /** Head reference. */ + @Nullable + PullRequestRef head(); + + /** Base reference. */ + @Nullable + PullRequestRef base(); +} diff --git a/src/main/java/com/spotify/github/v3/prs/PullRequest.java b/src/main/java/com/spotify/github/v3/prs/PullRequest.java index f0a91016..875ce19d 100644 --- a/src/main/java/com/spotify/github/v3/prs/PullRequest.java +++ b/src/main/java/com/spotify/github/v3/prs/PullRequest.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,8 +24,10 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.spotify.github.GithubStyle; import com.spotify.github.v3.User; + import java.util.Optional; import javax.annotation.Nullable; + import org.immutables.value.Value; /** @@ -77,7 +79,4 @@ public interface PullRequest extends PullRequestItem { /** The mergeable state of this PR. */ @Nullable String mergeableState(); - - /** Is it a draft PR? */ - Optional draft(); } diff --git a/src/main/java/com/spotify/github/v3/prs/PullRequestItem.java b/src/main/java/com/spotify/github/v3/prs/PullRequestItem.java index 452cf3b2..96830e77 100644 --- a/src/main/java/com/spotify/github/v3/prs/PullRequestItem.java +++ b/src/main/java/com/spotify/github/v3/prs/PullRequestItem.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,15 +23,17 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.spotify.github.CloseTracking; import com.spotify.github.GitHubInstant; import com.spotify.github.GithubStyle; import com.spotify.github.v3.Milestone; import com.spotify.github.v3.User; +import com.spotify.github.v3.issues.Label; + +import javax.annotation.Nullable; import java.net.URI; import java.util.List; import java.util.Optional; -import javax.annotation.Nullable; + import org.immutables.value.Value; /** Pull request item resource represents data returned during pull request list operation */ @@ -39,15 +41,7 @@ @GithubStyle @JsonSerialize(as = ImmutablePullRequestItem.class) @JsonDeserialize(as = ImmutablePullRequestItem.class) -public interface PullRequestItem extends CloseTracking { - - /** ID. */ - @Nullable - Integer id(); - - /** URL. */ - @Nullable - URI url(); +public interface PullRequestItem extends PartialPullRequestItem { /** HTML URL. */ @Nullable @@ -69,10 +63,6 @@ public interface PullRequestItem extends CloseTracking { @Nullable URI commitsUrl(); - /** Number. */ - @Nullable - Integer number(); - /** Either open, closed, or all to filter by state. Default: open. */ @Nullable String state(); @@ -100,14 +90,6 @@ public interface PullRequestItem extends CloseTracking { /** Merged date. */ Optional mergedAt(); - /** Head reference. */ - @Nullable - PullRequestRef head(); - - /** Base reference. */ - @Nullable - PullRequestRef base(); - /** User. */ @Nullable User user(); @@ -143,6 +125,23 @@ public interface PullRequestItem extends CloseTracking { @JsonProperty("requested_teams") List requestedTeams(); - /** @Deprecated the merge commit sha. */ + /** + * @Deprecated the merge commit sha. + */ Optional mergeCommitSha(); + + /** Node ID. */ + @Nullable + String nodeId(); + + /** Is Automerge Enabled */ + @Nullable + AutoMerge autoMerge(); + + /** Is it a draft PR? */ + Optional draft(); + + /** List of PR labels */ + @Nullable + List

The opencensus-testing library has a TestHandler that can be used in tests like this, but the + * only method it exposes to gain access to the received spans is waitForExport(int) which blocks + * forever until the given number of spans is exported, which could be never. So instead we define + * our own very simple implementation. + */ +class OtTestExportHandler implements SpanExporter { + private static final Logger LOG = LoggerFactory.getLogger(OtTestExportHandler.class); + + private final List receivedSpans = new ArrayList<>(); + private final Object lock = new Object(); + @Override + public CompletableResultCode export(Collection spanDataList) { + synchronized (lock) { + receivedSpans.addAll(spanDataList); + LOG.info("received {} spans, {} total", spanDataList.size(), receivedSpans.size()); + } + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + this.receivedSpans.clear(); + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } + + List receivedSpans() { + synchronized (lock) { + return new ArrayList<>(receivedSpans); + } + } + + /** Wait up to waitTime for at least `count` spans to be exported */ + List waitForSpansToBeExported(final int count) throws InterruptedException { + Duration waitTime = Duration.ofSeconds(7); + Instant deadline = Instant.now().plus(waitTime); + + List spanData = receivedSpans(); + while (spanData.size() < count) { + //noinspection BusyWait + Thread.sleep(100); + spanData = receivedSpans(); + + if (!Instant.now().isBefore(deadline)) { + LOG.warn("ending busy wait for spans because deadline passed"); + break; + } + } + return spanData; + } +} diff --git a/src/test/java/com/spotify/github/v3/activity/events/IssueCommentEventTest.java b/src/test/java/com/spotify/github/v3/activity/events/IssueCommentEventTest.java new file mode 100644 index 00000000..15d1c78d --- /dev/null +++ b/src/test/java/com/spotify/github/v3/activity/events/IssueCommentEventTest.java @@ -0,0 +1,49 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.activity.events; + +import java.io.IOException; +import static java.nio.charset.Charset.defaultCharset; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import org.junit.jupiter.api.Test; + +import com.google.common.io.Resources; +import static com.google.common.io.Resources.getResource; +import com.spotify.github.jackson.Json; + +public class IssueCommentEventTest { + + @Test + public void testDeserialization() throws IOException { + String fixture = + Resources.toString( + getResource(this.getClass(), "fixtures/issue_comment_event.json"), defaultCharset()); + final IssueCommentEvent event = Json.create().fromJson(fixture, IssueCommentEvent.class); + assertThat(event.action(), is("created")); + assertThat(event.issue().number(), is(2L)); + assertThat(event.comment().id(), is(99262140L)); + assertThat(event.comment().nodeId(), is("asd123")); + assertThat( + event.comment().body(), is("You are totally right! I'll get this fixed right away.")); + } +} diff --git a/src/test/java/com/spotify/github/v3/activity/events/MergeGroupEventTest.java b/src/test/java/com/spotify/github/v3/activity/events/MergeGroupEventTest.java new file mode 100644 index 00000000..c10c79e9 --- /dev/null +++ b/src/test/java/com/spotify/github/v3/activity/events/MergeGroupEventTest.java @@ -0,0 +1,53 @@ +/*- + * -\-\- + * github-client + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.activity.events; + +import static com.google.common.io.Resources.getResource; +import static java.nio.charset.Charset.defaultCharset; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.notNullValue; + +import com.google.common.io.Resources; +import com.spotify.github.jackson.Json; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +public class MergeGroupEventTest { + @Test + public void testDeserialization() throws IOException { + String fixture = + Resources.toString( + getResource(this.getClass(), "fixtures/merge_group_event.json"), + defaultCharset()); + final MergeGroupEvent mergeGroupEvent = + Json.create().fromJson(fixture, MergeGroupEvent.class); + assertThat(mergeGroupEvent.action(), is("checks_requested")); + assertThat(mergeGroupEvent.mergeGroup(), notNullValue()); + assertThat(mergeGroupEvent.mergeGroup().headSha(), is("cd84187b3e9a3e8f5b5f5b5f5b5f5b5f5b5f5b5f")); + assertThat(mergeGroupEvent.mergeGroup().headRef(), is("refs/heads/gh-readonly-queue/main/pr-123-cd84187b3e9a3e8f5b5f5b5f5b5f5b5f5b5f5b5f")); + assertThat(mergeGroupEvent.mergeGroup().baseSha(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b")); + assertThat(mergeGroupEvent.mergeGroup().baseRef(), is("refs/heads/main")); + assertThat(mergeGroupEvent.repository(), notNullValue()); + assertThat(mergeGroupEvent.repository().name(), is("public-repo")); + assertThat(mergeGroupEvent.repository().owner().login(), is("baxterthehacker")); + } +} \ No newline at end of file diff --git a/src/test/java/com/spotify/github/v3/activity/events/PullRequestReviewCommentEventTest.java b/src/test/java/com/spotify/github/v3/activity/events/PullRequestReviewCommentEventTest.java new file mode 100644 index 00000000..96bfde99 --- /dev/null +++ b/src/test/java/com/spotify/github/v3/activity/events/PullRequestReviewCommentEventTest.java @@ -0,0 +1,60 @@ +/*- + * -\-\- + * github-client + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.activity.events; + +import java.io.IOException; +import static java.nio.charset.Charset.defaultCharset; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import org.junit.jupiter.api.Test; + +import com.google.common.io.Resources; +import static com.google.common.io.Resources.getResource; +import com.spotify.github.jackson.Json; + +public class PullRequestReviewCommentEventTest { + @Test + public void testDeserialization() throws IOException { + String fixture = + Resources.toString( + getResource(this.getClass(), "fixtures/pull_request_review_comment_event.json"), + defaultCharset()); + final PullRequestReviewCommentEvent event = + Json.create().fromJson(fixture, PullRequestReviewCommentEvent.class); + assertThat(event.action(), is("created")); + assertThat(event.comment().id(), is(29724692L)); + assertThat(event.comment().nodeId(), is("abc234")); + assertThat(event.pullRequest().nodeId(), is("abc123")); + assertThat(event.comment().body(), is("Maybe you should use more emojji on this line.")); + assertThat(event.comment().originalCommitId(), is("0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c")); + assertThat(event.comment().originalLine(), is(1)); + assertThat(event.comment().originalPosition(), is(1)); + assertThat(event.comment().originalStartLine(), is(1)); + assertThat(event.comment().line(), is(1)); + assertThat(event.comment().side(), is("RIGHT")); + assertThat(event.comment().startLine(), is(1)); + assertThat(event.comment().startSide(), is("RIGHT")); + assertThat(event.comment().authorAssociation(), is("NONE")); + assertThat(event.comment().pullRequestReviewId(), is(42L)); + assertThat(event.comment().inReplyToId(), is(426899381L)); + } +} diff --git a/src/test/java/com/spotify/github/v3/activity/events/PullRequestReviewEventTest.java b/src/test/java/com/spotify/github/v3/activity/events/PullRequestReviewEventTest.java index b71ede72..4afb8fbf 100644 --- a/src/test/java/com/spotify/github/v3/activity/events/PullRequestReviewEventTest.java +++ b/src/test/java/com/spotify/github/v3/activity/events/PullRequestReviewEventTest.java @@ -40,7 +40,7 @@ public void testDeserialization() throws IOException { final PullRequestReviewEvent statusEvent = Json.create().fromJson(fixture, PullRequestReviewEvent.class); assertThat(statusEvent.action(), is("submitted")); - assertThat(statusEvent.pullRequest().number(), is(8)); + assertThat(statusEvent.pullRequest().number(), is(8L)); assertThat(statusEvent.review().state(), is(ReviewState.APPROVED)); } } diff --git a/src/test/java/com/spotify/github/v3/clients/GitDataClientTest.java b/src/test/java/com/spotify/github/v3/clients/GitDataClientTest.java index 4f87af26..1ef3dfdd 100644 --- a/src/test/java/com/spotify/github/v3/clients/GitDataClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/GitDataClientTest.java @@ -180,6 +180,25 @@ public void createTagReference() throws Exception { assertThat(reference.object().sha(), is("5926dd300de5fee31d445c57be223f00e128a634")); } + @Test + public void updateReference() throws Exception { + final CompletableFuture fixture = + completedFuture(json.fromJson(getFixture("branch.json"), Reference.class)); + final ImmutableMap body = + of( + "sha", "aa218f56b14c9653891f9e74264a383fa43fefbd", + "force", "false"); + when(github.patch( + "/repos/someowner/somerepo/git/refs/featureA", + github.json().toJsonUnchecked(body), + Reference.class)) + .thenReturn(fixture); + final Reference reference = + gitDataClient.updateReference("featureA", "aa218f56b14c9653891f9e74264a383fa43fefbd", false).get(); + assertThat(reference.ref(), is("refs/heads/featureA")); + assertThat(reference.object().sha(), is("aa218f56b14c9653891f9e74264a383fa43fefbd")); + } + @Test public void createAnnotateTag() throws Exception { final String now = Instant.now().toString(); diff --git a/src/test/java/com/spotify/github/v3/clients/GitHubAuthTest.java b/src/test/java/com/spotify/github/v3/clients/GitHubAuthTest.java index c5308407..5f9ce379 100644 --- a/src/test/java/com/spotify/github/v3/clients/GitHubAuthTest.java +++ b/src/test/java/com/spotify/github/v3/clients/GitHubAuthTest.java @@ -180,10 +180,10 @@ public void throwsIfFetchingInstallationTokenRequestIsUnsuccessful() throws Exce RuntimeException ex = assertThrows(RuntimeException.class, () -> checksClient.getCheckRun(123).join()); - assertThat(ex.getMessage(), is("Could not generate access token for github app")); + assertThat(ex.getCause().getMessage(), is("Could not generate access token for github app")); - assertThat(ex.getCause(), is(notNullValue())); - assertThat(ex.getCause().getMessage(), startsWith("Got non-2xx status 500 when getting an access token from GitHub")); + assertThat(ex.getCause().getCause(), is(notNullValue())); + assertThat(ex.getCause().getCause().getCause().getMessage(), startsWith("Got non-2xx status 500 when getting an access token from GitHub")); RecordedRequest recordedRequest = mockServer.takeRequest(1, TimeUnit.MILLISECONDS); // make sure it was the expected request that threw diff --git a/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java b/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java index 1492d126..8725958d 100644 --- a/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,6 +22,8 @@ import static com.google.common.io.Resources.getResource; import static java.nio.charset.Charset.defaultCharset; +import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.CompletableFuture.failedFuture; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsMapContaining.hasEntry; @@ -31,21 +33,27 @@ import static org.mockito.Mockito.*; import com.google.common.io.Resources; -import com.spotify.github.Tracer; +import com.spotify.github.http.HttpRequest; +import com.spotify.github.tracing.Span; +import com.spotify.github.tracing.Tracer; import com.spotify.github.v3.checks.CheckSuiteResponseList; +import com.spotify.github.v3.checks.Installation; import com.spotify.github.v3.exceptions.ReadOnlyRepositoryException; import com.spotify.github.v3.exceptions.RequestNotOkException; import com.spotify.github.v3.repos.CommitItem; import com.spotify.github.v3.repos.RepositoryInvitation; -import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.util.HashMap; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; + +import com.spotify.github.v3.workflows.WorkflowsResponse; +import com.spotify.github.v3.workflows.WorkflowsState; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Headers; @@ -55,6 +63,7 @@ import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -64,7 +73,8 @@ public class GitHubClientTest { private GitHubClient github; private OkHttpClient client; - private Tracer tracer = mock(Tracer.class); + private final Tracer tracer = mock(Tracer.class); + private final Span mockSpan = mock(Span.class); private static String getFixture(String resource) throws IOException { return Resources.toString(getResource(GitHubClientTest.class, resource), defaultCharset()); @@ -74,6 +84,7 @@ private static String getFixture(String resource) throws IOException { public void setUp() { client = mock(OkHttpClient.class); github = GitHubClient.create(client, URI.create("http://bogus"), "token"); + when(tracer.span(any())).thenReturn(mockSpan); } @Test @@ -83,7 +94,9 @@ public void withScopedInstallationIdShouldFailWhenMissingPrivateKey() { @Test public void testWithScopedInstallationId() throws URISyntaxException { - GitHubClient org = GitHubClient.create(new URI("http://apa.bepa.cepa"), "some_key_content".getBytes(), null, null); + GitHubClient org = + GitHubClient.create( + new URI("http://apa.bepa.cepa"), "some_key_content".getBytes(), null, null); GitHubClient scoped = org.withScopeForInstallationId(1); Assertions.assertTrue(scoped.getPrivateKey().isPresent()); Assertions.assertEquals(org.getPrivateKey().get(), scoped.getPrivateKey().get()); @@ -122,10 +135,9 @@ public void testSearchIssue() throws Throwable { CompletableFuture maybeSucceeded = issueClient.editComment(1, "some comment"); capture.getValue().onResponse(call, response); - verify(tracer,times(1)).span(anyString(), anyString(),any()); + verify(tracer, times(1)).span(any(HttpRequest.class)); - Exception exception = assertThrows(ExecutionException.class, - maybeSucceeded::get); + Exception exception = assertThrows(ExecutionException.class, maybeSucceeded::get); Assertions.assertEquals(ReadOnlyRepositoryException.class, exception.getCause().getClass()); } @@ -135,18 +147,17 @@ public void testRequestNotOkException() throws Throwable { final ArgumentCaptor capture = ArgumentCaptor.forClass(Callback.class); doNothing().when(call).enqueue(capture.capture()); - final Response response = new okhttp3.Response.Builder() - .code(409) // Conflict - .headers(Headers.of("x-ratelimit-remaining", "0")) - .body( - ResponseBody.create( - MediaType.get("application/json"), - "{\n \"message\": \"Merge Conflict\"\n}" - )) - .message("") - .protocol(Protocol.HTTP_1_1) - .request(new Request.Builder().url("http://localhost/").build()) - .build(); + final Response response = + new okhttp3.Response.Builder() + .code(409) // Conflict + .headers(Headers.of("x-ratelimit-remaining", "0")) + .body( + ResponseBody.create( + MediaType.get("application/json"), "{\n \"message\": \"Merge Conflict\"\n}")) + .message("") + .protocol(Protocol.HTTP_1_1) + .request(new Request.Builder().url("http://localhost/").build()) + .build(); when(client.newCall(any())).thenReturn(call); RepositoryClient repoApi = github.createRepositoryClient("testorg", "testrepo"); @@ -190,8 +201,8 @@ public void testPutConvertsToClass() throws Throwable { .request(new Request.Builder().url("http://localhost/").build()) .build(); - CompletableFuture future = github.put("collaborators/", "", - RepositoryInvitation.class); + CompletableFuture future = + github.put("collaborators/", "", RepositoryInvitation.class); callbackCapture.getValue().onResponse(call, response); RepositoryInvitation invitation = future.get(); @@ -207,15 +218,17 @@ public void testGetCheckSuites() throws Throwable { final ArgumentCaptor callbackCapture = ArgumentCaptor.forClass(Callback.class); doNothing().when(call).enqueue(callbackCapture.capture()); - final Response response = new okhttp3.Response.Builder() - .code(200) - .body( - ResponseBody.create( - MediaType.get("application/json"), getFixture("../checks/check-suites-response.json"))) - .message("") - .protocol(Protocol.HTTP_1_1) - .request(new Request.Builder().url("http://localhost/").build()) - .build(); + final Response response = + new okhttp3.Response.Builder() + .code(200) + .body( + ResponseBody.create( + MediaType.get("application/json"), + getFixture("../checks/check-suites-response.json"))) + .message("") + .protocol(Protocol.HTTP_1_1) + .request(new Request.Builder().url("http://localhost/").build()) + .build(); when(client.newCall(any())).thenReturn(call); ChecksClient client = github.createChecksClient("testorg", "testrepo"); @@ -226,6 +239,97 @@ public void testGetCheckSuites() throws Throwable { assertThat(result.totalCount(), is(1)); assertThat(result.checkSuites().get(0).app().get().slug().get(), is("octoapp")); + } + + @Test + public void testGetWorkflow() throws Throwable { + final Call call = mock(Call.class); + final ArgumentCaptor callbackCapture = ArgumentCaptor.forClass(Callback.class); + doNothing().when(call).enqueue(callbackCapture.capture()); + + final Response response = + new okhttp3.Response.Builder() + .code(200) + .body( + ResponseBody.create( + MediaType.get("application/json"), + getFixture("../workflows/workflows-get-workflow-response.json"))) + .message("") + .protocol(Protocol.HTTP_1_1) + .request(new Request.Builder().url("http://localhost/").build()) + .build(); + + when(client.newCall(any())).thenReturn(call); + WorkflowsClient client = + github + .withTracer(tracer) + .createRepositoryClient("testorg", "testrepo") + .createActionsClient() + .createWorkflowsClient(); + + CompletableFuture future = client.getWorkflow(161335); + callbackCapture.getValue().onResponse(call, response); + var result = future.get(); + + assertThat(result.id(), is(161335)); + assertThat(result.state(), is(WorkflowsState.active)); + } + + @Test + void asAppScopedClientGetsUserClientIfOrgClientNotFound() { + var appGithub = GitHubClient.create(client, URI.create("http://bogus"), new byte[] {}, 1); + var githubSpy = spy(appGithub); + + var orgClientMock = mock(OrganisationClient.class); + when(githubSpy.createOrganisationClient("owner")).thenReturn(orgClientMock); + + var appClientMock = mock(GithubAppClient.class); + when(orgClientMock.createGithubAppClient()).thenReturn(appClientMock); + when(appClientMock.getInstallation()) + .thenReturn(failedFuture(new RequestNotOkException("", "", 404, "", new HashMap<>()))); + + var userClientMock = mock(UserClient.class); + when(githubSpy.createUserClient("owner")).thenReturn(userClientMock); + + var appClientMock2 = mock(GithubAppClient.class); + when(userClientMock.createGithubAppClient()).thenReturn(appClientMock2); + + var installationMock = mock(Installation.class); + when(appClientMock2.getUserInstallation()).thenReturn(completedFuture(installationMock)); + when(installationMock.id()).thenReturn(1); + + var maybeScopedClient = githubSpy.asAppScopedClient("owner").toCompletableFuture().join(); + + Assertions.assertTrue(maybeScopedClient.isPresent()); + verify(githubSpy, times(1)).createOrganisationClient("owner"); + verify(githubSpy, times(1)).createUserClient("owner"); + } + + @Test + void asAppScopedClientReturnsEmptyIfNoInstallation() { + var appGithub = GitHubClient.create(client, URI.create("http://bogus"), new byte[] {}, 1); + var githubSpy = spy(appGithub); + + var orgClientMock = mock(OrganisationClient.class); + when(githubSpy.createOrganisationClient("owner")).thenReturn(orgClientMock); + + var appClientMock = mock(GithubAppClient.class); + when(orgClientMock.createGithubAppClient()).thenReturn(appClientMock); + when(appClientMock.getInstallation()) + .thenReturn(failedFuture(new RequestNotOkException("", "", 404, "", new HashMap<>()))); + + var userClientMock = mock(UserClient.class); + when(githubSpy.createUserClient("owner")).thenReturn(userClientMock); + + var appClientMock2 = mock(GithubAppClient.class); + when(userClientMock.createGithubAppClient()).thenReturn(appClientMock2); + + var installationMock = mock(Installation.class); + when(appClientMock2.getUserInstallation()) + .thenReturn(failedFuture(new RequestNotOkException("", "", 404, "", new HashMap<>()))); + when(installationMock.id()).thenReturn(1); + var maybeScopedClient = githubSpy.asAppScopedClient("owner").toCompletableFuture().join(); + Assertions.assertTrue(maybeScopedClient.isEmpty()); } } diff --git a/src/test/java/com/spotify/github/v3/clients/GitHubPageTest.java b/src/test/java/com/spotify/github/v3/clients/GitHubPageTest.java new file mode 100644 index 00000000..295a4d76 --- /dev/null +++ b/src/test/java/com/spotify/github/v3/clients/GitHubPageTest.java @@ -0,0 +1,53 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2025 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.clients; + +import static org.hamcrest.core.Is.is; + +import java.net.URI; +import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresentAndIs; +import static com.github.npathai.hamcrestopt.OptionalMatchers.isEmpty; + +public class GitHubPageTest { + private static final String MOCK_GITHUB_HOST = "bogus.host"; + private static final URI MOCK_GITHUB_URI = URI.create(String.format("http://%s/api/v3/", MOCK_GITHUB_HOST)); + + @Test + public void testFormatPathWithPerPage() { + assertThat(GithubPage.formatPath("/commits?page=2", 3), is("/commits?page=2&per_page=3")); + assertThat(GithubPage.formatPath("NOT_A_CORRECT PATH ", 3), is("NOT_A_CORRECT PATH ")); + assertThat(GithubPage.formatPath("/commits", 3), is("/commits?per_page=3")); + assertThat(GithubPage.formatPath("/commits?page=2&per_page=7", 3), is("/commits?page=2&per_page=7")); + } + + @Test + public void testPageNumberFromURI() { + assertThat(GithubPage.pageNumberFromUri(MOCK_GITHUB_URI.resolve("/commits?page=5").toString()), isPresentAndIs(5)); + assertThat(GithubPage.pageNumberFromUri(MOCK_GITHUB_URI.resolve("/commits").toString()), isEmpty()); + assertThat(GithubPage.pageNumberFromUri(MOCK_GITHUB_URI.resolve("commits").toString()), isEmpty()); + assertThat(GithubPage.pageNumberFromUri("/commits?page=2"), isPresentAndIs(2)); + assertThat(GithubPage.pageNumberFromUri("/commits?per_page=4&page=2"), isPresentAndIs(2)); + assertThat(GithubPage.pageNumberFromUri("NOT_A_CORRECT PATH "), isEmpty()); + assertThat(GithubPage.pageNumberFromUri("/commits"), isEmpty()); + } +} diff --git a/src/test/java/com/spotify/github/v3/clients/GithubAppClientTest.java b/src/test/java/com/spotify/github/v3/clients/GithubAppClientTest.java index 62e92757..c47d3a4d 100644 --- a/src/test/java/com/spotify/github/v3/clients/GithubAppClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/GithubAppClientTest.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,12 +24,17 @@ import static java.nio.charset.Charset.defaultCharset; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.core.Is.is; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.io.Resources; import com.spotify.github.FixtureHelper; import com.spotify.github.v3.apps.InstallationRepositoriesResponse; +import com.spotify.github.v3.apps.requests.AccessTokenRequest; +import com.spotify.github.v3.apps.requests.ImmutableAccessTokenRequest; +import com.spotify.github.v3.checks.AccessToken; +import com.spotify.github.v3.checks.App; import com.spotify.github.v3.checks.Installation; import java.io.File; import java.io.IOException; @@ -110,8 +115,7 @@ public void listAccessibleRepositories() throws Exception { .setResponseCode(200) .setBody(FixtureHelper.loadFixture("githubapp/accessible-repositories.json"))); - InstallationRepositoriesResponse response = - client.listAccessibleRepositories(1234).join(); + InstallationRepositoriesResponse response = client.listAccessibleRepositories(1234).join(); assertThat(response.totalCount(), is(2)); assertThat(response.repositories().size(), is(2)); @@ -160,4 +164,90 @@ public void getInstallationByInstallationId() throws Exception { RecordedRequest recordedRequest = mockServer.takeRequest(1, TimeUnit.MILLISECONDS); assertThat(recordedRequest.getRequestUrl().encodedPath(), is("/app/installations/1234")); } + + @Test + public void getAuthenticatedApp() throws Exception { + mockServer.enqueue( + new MockResponse() + .setResponseCode(200) + .setBody(FixtureHelper.loadFixture("githubapp/authenticated-app.json"))); + + App app = client.getAuthenticatedApp().join(); + + assertThat(app.id(), is(1)); + assertThat(app.slug().get(), is("octoapp")); + assertThat(app.name(), is("Octocat App")); + assertThat(app.clientId().get(), is("Iv1.8a61f9b3a7aba766")); + assertThat(app.installationsCount().get(), is(5)); + + RecordedRequest recordedRequest = mockServer.takeRequest(1, TimeUnit.MILLISECONDS); + assertThat(recordedRequest.getRequestUrl().encodedPath(), is("/app")); + assertThat( + recordedRequest.getHeaders().values("Authorization").get(0).startsWith("Bearer "), + is(true)); + } + + @Test + public void getAccessTokenWithoutScoping() throws Exception { + mockServer.enqueue( + new MockResponse() + .setResponseCode(201) + .setBody(FixtureHelper.loadFixture("githubapp/access-token.json"))); + + AccessToken token = client.getAccessToken(1234).join(); + + assertThat(token.token(), is("ghs_16C7e42F292c6912E7710c838347Ae178B4a")); + + RecordedRequest recordedRequest = mockServer.takeRequest(1, TimeUnit.MILLISECONDS); + assertThat(recordedRequest.getMethod(), is("POST")); + assertThat( + recordedRequest.getRequestUrl().encodedPath(), + is("/app/installations/1234/access_tokens")); + assertThat(recordedRequest.getBody().readUtf8(), is("")); + } + + @Test + public void getAccessTokenWithRepositoryScoping() throws Exception { + mockServer.enqueue( + new MockResponse() + .setResponseCode(201) + .setBody(FixtureHelper.loadFixture("githubapp/access-token.json"))); + + AccessTokenRequest request = ImmutableAccessTokenRequest.builder() + .repositories(List.of("Hello-World")) + .repositoryIds(List.of(1)) + .build(); + + AccessToken token = client.getAccessToken(1234, request).join(); + + assertThat(token.token(), is("ghs_16C7e42F292c6912E7710c838347Ae178B4a")); + + RecordedRequest recordedRequest = mockServer.takeRequest(1, TimeUnit.MILLISECONDS); + assertThat(recordedRequest.getMethod(), is("POST")); + assertThat( + recordedRequest.getRequestUrl().encodedPath(), + is("/app/installations/1234/access_tokens")); + + String requestBody = recordedRequest.getBody().readUtf8(); + assertThat(requestBody, containsString("\"repositories\":[\"Hello-World\"]")); + assertThat(requestBody, containsString("\"repository_ids\":[1]")); + } + + @Test + public void getAccessTokenWithEmptyRequest() throws Exception { + mockServer.enqueue( + new MockResponse() + .setResponseCode(201) + .setBody(FixtureHelper.loadFixture("githubapp/access-token.json"))); + + AccessTokenRequest emptyRequest = ImmutableAccessTokenRequest.builder().build(); + + AccessToken token = client.getAccessToken(1234, emptyRequest).join(); + + assertThat(token.token(), is("ghs_16C7e42F292c6912E7710c838347Ae178B4a")); + + RecordedRequest recordedRequest = mockServer.takeRequest(1, TimeUnit.MILLISECONDS); + String requestBody = recordedRequest.getBody().readUtf8(); + assertThat(requestBody, is("{}")); + } } diff --git a/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java b/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java index dc7d1939..65ac3054 100644 --- a/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,40 +22,58 @@ import static com.google.common.io.Resources.getResource; import static com.spotify.github.FixtureHelper.loadFixture; -import static com.spotify.github.v3.clients.IssueClient.COMMENTS_URI_NUMBER_TEMPLATE; -import static com.spotify.github.v3.clients.MockHelper.createMockResponse; +import static com.spotify.github.v3.clients.IssueClient.*; +import static com.spotify.github.MockHelper.createMockResponse; import static java.lang.String.format; import static java.nio.charset.Charset.defaultCharset; import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.CompletableFuture.failedFuture; import static java.util.stream.Collectors.toList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.io.Resources; import com.spotify.github.async.Async; import com.spotify.github.async.AsyncPage; +import com.spotify.github.http.HttpResponse; import com.spotify.github.jackson.Json; +import com.spotify.github.v3.ImmutableUser; import com.spotify.github.v3.comment.Comment; +import com.spotify.github.v3.comment.CommentReaction; +import com.spotify.github.v3.comment.CommentReactionContent; +import com.spotify.github.v3.comment.ImmutableCommentReaction; +import com.spotify.github.v3.exceptions.RequestNotOkException; +import com.spotify.github.v3.issues.Issue; import java.io.IOException; +import java.util.HashMap; import java.util.List; -import okhttp3.Response; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; public class IssueClientTest { private GitHubClient github; private IssueClient issueClient; + private Json json; @BeforeEach public void setUp() { + json = Json.create(); github = mock(GitHubClient.class); - when(github.json()).thenReturn(Json.create()); + when(github.json()).thenReturn(json); when(github.urlFor("")).thenReturn("https://github.com/api/v3"); issueClient = new IssueClient(github, "someowner", "somerepo"); } @@ -63,29 +81,35 @@ public void setUp() { @Test public void testCommentPaginationSpliterator() throws IOException { final String firstPageLink = - "; rel=\"next\", ; rel=\"last\""; + "; rel=\"next\", ; rel=\"last\""; final String firstPageBody = Resources.toString(getResource(this.getClass(), "comments_page1.json"), defaultCharset()); - final Response firstPageResponse = createMockResponse(firstPageLink, firstPageBody); + final HttpResponse firstPageResponse = createMockResponse(firstPageLink, firstPageBody); final String lastPageLink = - "; rel=\"first\", ; rel=\"prev\""; + "; rel=\"first\", ; rel=\"prev\""; final String lastPageBody = Resources.toString(getResource(this.getClass(), "comments_page2.json"), defaultCharset()); - final Response lastPageResponse = createMockResponse(lastPageLink, lastPageBody); + final HttpResponse lastPageResponse = createMockResponse(lastPageLink, lastPageBody); - when(github.request(format(COMMENTS_URI_NUMBER_TEMPLATE, "someowner", "somerepo", "123"))) + when(github.request( + format(COMMENTS_URI_NUMBER_TEMPLATE + "?per_page=30", "someowner", "somerepo", "123"))) .thenReturn(completedFuture(firstPageResponse)); when(github.request( - format(COMMENTS_URI_NUMBER_TEMPLATE + "?page=2", "someowner", "somerepo", "123"))) + format( + COMMENTS_URI_NUMBER_TEMPLATE + "?page=2&per_page=30", + "someowner", + "somerepo", + "123"))) .thenReturn(completedFuture(lastPageResponse)); final Iterable> pageIterator = () -> issueClient.listComments(123); - final List listComments = Async.streamFromPaginatingIterable(pageIterator).collect(toList()); + final List listComments = + Async.streamFromPaginatingIterable(pageIterator).collect(toList()); assertThat(listComments.size(), is(30)); - assertThat(listComments.get(0).id(), is(1345268)); - assertThat(listComments.get(listComments.size() - 1).id(), is(1356168)); + assertThat(listComments.get(0).id(), is(1345268L)); + assertThat(listComments.get(listComments.size() - 1).id(), is(1356168L)); } @Test @@ -94,18 +118,23 @@ public void testCommentPaginationForeach() throws IOException { "; rel=\"next\", ; rel=\"last\""; final String firstPageBody = Resources.toString(getResource(this.getClass(), "comments_page1.json"), defaultCharset()); - final Response firstPageResponse = createMockResponse(firstPageLink, firstPageBody); + final HttpResponse firstPageResponse = createMockResponse(firstPageLink, firstPageBody); final String lastPageLink = "; rel=\"first\", ; rel=\"prev\""; final String lastPageBody = Resources.toString(getResource(this.getClass(), "comments_page2.json"), defaultCharset()); - final Response lastPageResponse = createMockResponse(lastPageLink, lastPageBody); + final HttpResponse lastPageResponse = createMockResponse(lastPageLink, lastPageBody); - when(github.request(format(COMMENTS_URI_NUMBER_TEMPLATE, "someowner", "somerepo", "123"))) + when(github.request( + format(COMMENTS_URI_NUMBER_TEMPLATE + "?per_page=30", "someowner", "somerepo", "123"))) .thenReturn(completedFuture(firstPageResponse)); when(github.request( - format(COMMENTS_URI_NUMBER_TEMPLATE + "?page=2", "someowner", "somerepo", "123"))) + format( + COMMENTS_URI_NUMBER_TEMPLATE + "?page=2&per_page=30", + "someowner", + "somerepo", + "123"))) .thenReturn(completedFuture(lastPageResponse)); final List listComments = Lists.newArrayList(); @@ -117,19 +146,180 @@ public void testCommentPaginationForeach() throws IOException { }); assertThat(listComments.size(), is(30)); - assertThat(listComments.get(0).id(), is(1345268)); - assertThat(listComments.get(listComments.size() - 1).id(), is(1356168)); + assertThat(listComments.get(0).id(), is(1345268L)); + assertThat(listComments.get(listComments.size() - 1).id(), is(1356168L)); } @Test public void testCommentCreated() throws IOException { final String fixture = loadFixture("clients/comment_created.json"); - final Response response = createMockResponse("", fixture); + final HttpResponse response = createMockResponse("", fixture); + final String path = format(COMMENTS_URI_NUMBER_TEMPLATE, "someowner", "somerepo", 10); + when(github.post(anyString(), anyString(), eq(Comment.class))).thenCallRealMethod(); + when(github.post(eq(path), anyString())).thenReturn(completedFuture(response)); + final Comment comment = issueClient.createComment(10, "Me too").join(); + + assertThat(comment.id(), is(114L)); + } + + @Test + public void testCommentCreatedWithLargeId() throws IOException { + final String fixture = loadFixture("clients/comment_created_long_id.json"); + final HttpResponse response = createMockResponse("", fixture); final String path = format(COMMENTS_URI_NUMBER_TEMPLATE, "someowner", "somerepo", 10); when(github.post(anyString(), anyString(), eq(Comment.class))).thenCallRealMethod(); when(github.post(eq(path), anyString())).thenReturn(completedFuture(response)); final Comment comment = issueClient.createComment(10, "Me too").join(); - assertThat(comment.id(), is(114)); + assertThat(comment.id(), is(2459198527L)); + } + + @Test + public void testGetIssue() throws IOException { + final String fixture = loadFixture("issues/issue.json"); + final CompletableFuture response = completedFuture(json.fromJson(fixture, Issue.class)); + final String path = format(ISSUES_URI_ID_TEMPLATE, "someowner", "somerepo", 2); + when(github.request(eq(path), eq(Issue.class))).thenReturn(response); + + final var issue = issueClient.getIssue(2).join(); + + assertThat(issue.id(), is(2L)); + assertNotNull(issue.labels()); + assertFalse(issue.labels().isEmpty()); + assertThat(issue.labels().get(0).name(), is("bug")); + } + + @ParameterizedTest + @EnumSource(CommentReactionContent.class) + public void testCreateIssueCommentReaction(CommentReactionContent reaction) { + long commentId = 22369886; + final CompletableFuture reactionResponse = + completedFuture( + ImmutableCommentReaction.builder() + .id(42L) + .content(reaction) + .user(ImmutableUser.builder().login("octocat").build()) + .build()); + final String path = format(COMMENTS_REACTION_TEMPLATE, "someowner", "somerepo", commentId); + final String requestBody = + github.json().toJsonUnchecked(ImmutableMap.of("content", reaction.toString())); + when(github.post(eq(path), eq(requestBody), eq(CommentReaction.class))) + .thenReturn(reactionResponse); + + final var commentReaction = issueClient.createCommentReaction(commentId, reaction).join(); + + assertThat(commentReaction.id(), is(42L)); + assertNotNull(commentReaction.user()); + assertThat(commentReaction.user().login(), is("octocat")); + assertThat(commentReaction.content().toString(), is(reaction.toString())); + verify(github, times(1)).post(eq(path), eq(requestBody), eq(CommentReaction.class)); + } + + @Test + public void testDeleteIssueCommentReaction() { + long commentId = 42; + long reactionId = 385825; + final String path = + format(COMMENTS_REACTION_ID_TEMPLATE, "someowner", "somerepo", commentId, reactionId); + HttpResponse mockResponse = mock(HttpResponse.class); + when(mockResponse.statusCode()).thenReturn(204); + when(github.delete(eq(path))).thenReturn(completedFuture(mockResponse)); + + final var response = issueClient.deleteCommentReaction(commentId, reactionId).join(); + + assertThat(response.statusCode(), is(204)); + assertThat(response, is(mockResponse)); + verify(github, times(1)).delete(eq(path)); + } + + @Test + public void testListIssueCommentReaction() throws IOException { + long commentId = 22369886; + final CompletableFuture> listResponse = + completedFuture( + List.of( + (ImmutableCommentReaction.builder() + .id(42L) + .content(CommentReactionContent.HEART) + .user(ImmutableUser.builder().login("octocat").build()) + .build()))); + final String path = + format(COMMENTS_REACTION_TEMPLATE + "?per_page=30", "someowner", "somerepo", commentId); + + final String firstPageLink = + format( + "; rel=\"last\"", + commentId); + final String firstPageBody = github.json().toJsonUnchecked(listResponse.join().toArray()); + final HttpResponse firstPageResponse = createMockResponse(firstPageLink, firstPageBody); + + when(github.request(eq(path))).thenReturn(completedFuture(firstPageResponse)); + final List listCommentReactions = Lists.newArrayList(); + issueClient + .listCommentReaction(commentId) + .forEachRemaining( + page -> { + page.iterator().forEachRemaining(listCommentReactions::add); + }); + + assertThat(listCommentReactions.size(), is(1)); + assertNotNull(listCommentReactions.get(0)); + assertThat(listCommentReactions.get(0).user().login(), is("octocat")); + assertThat( + listCommentReactions.get(0).content().toString(), + is(CommentReactionContent.HEART.toString())); + verify(github, atLeastOnce()).request(eq(path)); + } + + @ParameterizedTest + @EnumSource(CommentReactionContent.class) + public void testCreateIssueReaction(CommentReactionContent reaction) { + long issueNumber = 42; + final CompletableFuture reactionResponse = + completedFuture( + ImmutableCommentReaction.builder() + .id(123L) + .content(reaction) + .user(ImmutableUser.builder().login("octocat").build()) + .build()); + final String path = format(ISSUES_REACTION_TEMPLATE, "someowner", "somerepo", issueNumber); + final String requestBody = + github.json().toJsonUnchecked(ImmutableMap.of("content", reaction.toString())); + when(github.post(eq(path), eq(requestBody), eq(CommentReaction.class))) + .thenReturn(reactionResponse); + + final var issueReaction = issueClient.createIssueReaction(issueNumber, reaction).join(); + + assertThat(issueReaction.id(), is(123L)); + assertNotNull(issueReaction.user()); + assertThat(issueReaction.user().login(), is("octocat")); + assertThat(issueReaction.content().toString(), is(reaction.toString())); + verify(github, times(1)).post(eq(path), eq(requestBody), eq(CommentReaction.class)); + } + + @Test + public void testDeleteIssueReaction() { + long issueNumber = 42; + long reactionId = 385825; + final String path = + format(ISSUES_REACTION_ID_TEMPLATE, "someowner", "somerepo", issueNumber, reactionId); + HttpResponse mockResponse = mock(HttpResponse.class); + when(mockResponse.statusCode()).thenReturn(204); + when(github.delete(eq(path))).thenReturn(completedFuture(mockResponse)); + + final var response = issueClient.deleteIssueReaction(issueNumber, reactionId).join(); + + assertThat(response.statusCode(), is(204)); + assertThat(response, is(mockResponse)); + verify(github, times(1)).delete(eq(path)); + } + + @Test + public void testGetIssueNoIssue() { + final String path = format(ISSUES_URI_ID_TEMPLATE, "someowner", "somerepo", 2); + when(github.request(eq(path), eq(Issue.class))) + .thenReturn(failedFuture(new RequestNotOkException("", "", 404, "", new HashMap<>()))); + + assertThrows(CompletionException.class, () -> issueClient.getIssue(2).join()); } } diff --git a/src/test/java/com/spotify/github/v3/clients/MockHelper.java b/src/test/java/com/spotify/github/v3/clients/MockHelper.java deleted file mode 100644 index 3bb896ca..00000000 --- a/src/test/java/com/spotify/github/v3/clients/MockHelper.java +++ /dev/null @@ -1,45 +0,0 @@ -/*- - * -\-\- - * github-client - * -- - * Copyright (C) 2016 - 2020 Spotify AB - * -- - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * -/-/- - */ - -package com.spotify.github.v3.clients; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import okhttp3.Headers; -import okhttp3.Response; -import okhttp3.ResponseBody; - -public class MockHelper { - public static Response createMockResponse(final String headerLinksFixture, final String bodyFixture) - throws IOException { - final ResponseBody body = mock(ResponseBody.class); - when(body.string()).thenReturn(bodyFixture); - - final Headers headers = mock(Headers.class); - when(headers.get("Link")).thenReturn(headerLinksFixture); - - final Response response = mock(Response.class); - when(response.headers()).thenReturn(headers); - when(response.body()).thenReturn(body); - return response; - } -} \ No newline at end of file diff --git a/src/test/java/com/spotify/github/v3/clients/PullRequestClientTest.java b/src/test/java/com/spotify/github/v3/clients/PullRequestClientTest.java index 0fdbd67f..a203a602 100644 --- a/src/test/java/com/spotify/github/v3/clients/PullRequestClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/PullRequestClientTest.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,40 +21,66 @@ package com.spotify.github.v3.clients; import static com.google.common.io.Resources.getResource; +import static com.spotify.github.MockHelper.createMockResponse; +import static java.lang.String.format; import static java.nio.charset.Charset.defaultCharset; +import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.stream.Collectors.toList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableList; import com.google.common.io.Resources; +import com.spotify.github.async.Async; +import com.spotify.github.async.AsyncPage; +import com.spotify.github.http.HttpResponse; +import com.spotify.github.jackson.Json; import com.spotify.github.v3.exceptions.RequestNotOkException; +import com.spotify.github.v3.git.FileItem; +import com.spotify.github.v3.git.ImmutableFileItem; +import com.spotify.github.v3.prs.Comment; import com.spotify.github.v3.prs.ImmutableRequestReviewParameters; -import com.spotify.github.v3.prs.MergeMethod; import com.spotify.github.v3.prs.PullRequest; import com.spotify.github.v3.prs.ReviewRequests; import com.spotify.github.v3.prs.requests.ImmutablePullRequestCreate; import com.spotify.github.v3.prs.requests.ImmutablePullRequestUpdate; import com.spotify.github.v3.prs.requests.PullRequestCreate; import com.spotify.github.v3.prs.requests.PullRequestUpdate; +import com.spotify.github.v3.repos.CommitItem; import java.io.IOException; import java.io.Reader; import java.net.URI; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; - -import okhttp3.*; -import okio.Buffer; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; public class PullRequestClientTest { + private static final String MOCK_GITHUB_HOST = "bogus.host"; + private static final URI MOCK_GITHUB_URI = + URI.create(String.format("http://%s/api/v3", MOCK_GITHUB_HOST)); + private static final URI MOCK_GITHUB_URI_GQL = MOCK_GITHUB_URI.resolve("/graphql"); + private static final String PR_CHANGED_FILES_TEMPLATE = "/repos/%s/%s/pulls/%s/files"; private GitHubClient github; + private GitHubClient mockGithub; private OkHttpClient client; private static String getFixture(String resource) throws IOException { @@ -64,7 +90,8 @@ private static String getFixture(String resource) throws IOException { @BeforeEach public void setUp() { client = mock(OkHttpClient.class); - github = GitHubClient.create(client, URI.create("http://bogus"), URI.create("https://bogus/graphql"), "token"); + github = GitHubClient.create(client, MOCK_GITHUB_URI, MOCK_GITHUB_URI_GQL, "token"); + mockGithub = mock(GitHubClient.class); } @Test @@ -85,18 +112,16 @@ public void createPullRequest() throws Exception { .message("Created") .body( ResponseBody.create( - MediaType.get("application/json"), - getFixture("pull_request.json"))) + MediaType.get("application/json"), getFixture("pull_request.json"))) .request(new Request.Builder().url("http://localhost/").build()) .build(); when(client.newCall(any())).thenReturn(call); - final PullRequestClient pullRequestClient = - PullRequestClient.create(github, "owner", "repo"); + final PullRequestClient pullRequestClient = PullRequestClient.create(github, "owner", "repo"); - final PullRequestCreate request = ImmutablePullRequestCreate.builder().title(title).body(body) - .head(head).base(base).build(); + final PullRequestCreate request = + ImmutablePullRequestCreate.builder().title(title).body(body).head(head).base(base).build(); final CompletableFuture result = pullRequestClient.create(request); @@ -126,20 +151,18 @@ public void updatePullRequest() throws Exception { .message("OK") .body( ResponseBody.create( - MediaType.get("application/json"), - getFixture("pull_request.json"))) + MediaType.get("application/json"), getFixture("pull_request.json"))) .request(new Request.Builder().url("http://localhost/").build()) .build(); when(client.newCall(any())).thenReturn(call); - final PullRequestClient pullRequestClient = - PullRequestClient.create(github, "owner", "repo"); + final PullRequestClient pullRequestClient = PullRequestClient.create(github, "owner", "repo"); - final PullRequestUpdate request = ImmutablePullRequestUpdate.builder().title(title).body(body) - .build(); + final PullRequestUpdate request = + ImmutablePullRequestUpdate.builder().title(title).body(body).build(); - final CompletableFuture result = pullRequestClient.update(1, request); + final CompletableFuture result = pullRequestClient.update(1L, request); capture.getValue().onResponse(call, response); @@ -162,18 +185,15 @@ public void testListReviewRequests() throws Throwable { .message("OK") .body( ResponseBody.create( - MediaType.get("application/json"), - getFixture("requestedReviews.json"))) + MediaType.get("application/json"), getFixture("requestedReviews.json"))) .request(new Request.Builder().url("http://localhost/").build()) .build(); when(client.newCall(any())).thenReturn(call); - final PullRequestClient pullRequestClient = - PullRequestClient.create(github, "owner", "repo"); + final PullRequestClient pullRequestClient = PullRequestClient.create(github, "owner", "repo"); - final CompletableFuture result = - pullRequestClient.listReviewRequests(1); + final CompletableFuture result = pullRequestClient.listReviewRequests(1L); capture.getValue().onResponse(call, response); @@ -202,13 +222,14 @@ public void testRemoveRequestedReview() throws Throwable { when(client.newCall(any())).thenReturn(call); - PullRequestClient pullRequestClient = - PullRequestClient.create(github, "owner", "repo"); + PullRequestClient pullRequestClient = PullRequestClient.create(github, "owner", "repo"); CompletableFuture result = - pullRequestClient.removeRequestedReview(1, ImmutableRequestReviewParameters.builder() - .reviewers(ImmutableList.of("user1", "user2")) - .build()); + pullRequestClient.removeRequestedReview( + 1L, + ImmutableRequestReviewParameters.builder() + .reviewers(ImmutableList.of("user1", "user2")) + .build()); capture.getValue().onResponse(call, response); @@ -233,13 +254,14 @@ public void testRemoveRequestedReview_failure() throws Throwable { when(client.newCall(any())).thenReturn(call); - PullRequestClient pullRequestClient = - PullRequestClient.create(github, "owner", "repo"); + PullRequestClient pullRequestClient = PullRequestClient.create(github, "owner", "repo"); CompletableFuture result = - pullRequestClient.removeRequestedReview(1, ImmutableRequestReviewParameters.builder() - .reviewers(ImmutableList.of("user1", "user2")) - .build()); + pullRequestClient.removeRequestedReview( + 1L, + ImmutableRequestReviewParameters.builder() + .reviewers(ImmutableList.of("user1", "user2")) + .build()); capture.getValue().onResponse(call, response); @@ -260,18 +282,15 @@ public void testGetPatch() throws Throwable { .message("OK") .body( ResponseBody.create( - MediaType.get("application/vnd.github.patch"), - getFixture("patch.txt"))) + MediaType.get("application/vnd.github.patch"), getFixture("patch.txt"))) .request(new Request.Builder().url("http://localhost/").build()) .build(); when(client.newCall(any())).thenReturn(call); - final PullRequestClient pullRequestClient = - PullRequestClient.create(github, "owner", "repo"); + final PullRequestClient pullRequestClient = PullRequestClient.create(github, "owner", "repo"); - final CompletableFuture result = - pullRequestClient.patch(1); + final CompletableFuture result = pullRequestClient.patch(1L); capture.getValue().onResponse(call, response); @@ -293,18 +312,15 @@ public void testGetDiff() throws Throwable { .message("OK") .body( ResponseBody.create( - MediaType.get("application/vnd.github.diff"), - getFixture("diff.txt"))) + MediaType.get("application/vnd.github.diff"), getFixture("diff.txt"))) .request(new Request.Builder().url("http://localhost/").build()) .build(); when(client.newCall(any())).thenReturn(call); - final PullRequestClient pullRequestClient = - PullRequestClient.create(github, "owner", "repo"); + final PullRequestClient pullRequestClient = PullRequestClient.create(github, "owner", "repo"); - final CompletableFuture result = - pullRequestClient.diff(1); + final CompletableFuture result = pullRequestClient.diff(1L); capture.getValue().onResponse(call, response); @@ -312,4 +328,267 @@ public void testGetDiff() throws Throwable { assertEquals(getFixture("diff.txt"), IOUtils.toString(diffReader)); } + + @Test + public void testCreateCommentReply() throws Throwable { + final Call call = mock(Call.class); + final ArgumentCaptor capture = ArgumentCaptor.forClass(Callback.class); + doNothing().when(call).enqueue(capture.capture()); + + final Response response = + new Response.Builder() + .code(201) + .protocol(Protocol.HTTP_1_1) + .message("Created") + .body( + ResponseBody.create( + MediaType.get("application/json"), + getFixture("pull_request_review_comment_reply.json"))) + .request(new Request.Builder().url("http://localhost/").build()) + .build(); + + when(client.newCall(any())).thenReturn(call); + + final PullRequestClient pullRequestClient = PullRequestClient.create(github, "owner", "repo"); + + final String replyBody = "Thanks for the feedback!"; + final CompletableFuture result = + pullRequestClient.createCommentReply(1L, 123L, replyBody); + + capture.getValue().onResponse(call, response); + + Comment comment = result.get(); + + assertThat(comment.body(), is("Great stuff!")); + assertThat(comment.id(), is(10L)); + assertThat( + comment.diffHunk(), is("@@ -16,33 +16,40 @@ public class Connection : IConnection...")); + assertThat(comment.path(), is("file1.txt")); + assertThat(comment.position(), is(1)); + assertThat(comment.originalPosition(), is(4)); + assertThat(comment.commitId(), is("6dcb09b5b57875f334f61aebed695e2e4193db5e")); + assertThat(comment.originalCommitId(), is("9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840")); + assertThat(comment.inReplyToId(), is(426899381L)); + assertThat(comment.authorAssociation(), is("NONE")); + assertThat(comment.user().login(), is("octocat")); + assertThat(comment.startLine(), is(1)); + assertThat(comment.originalStartLine(), is(1)); + assertThat(comment.startSide(), is("RIGHT")); + assertThat(comment.line(), is(2)); + assertThat(comment.originalLine(), is(2)); + assertThat(comment.side(), is("RIGHT")); + assertThat(comment.pullRequestReviewId(), is(42L)); + } + + @Test + void testChangedFiles() throws IOException { + FileItem file1 = + ImmutableFileItem.builder() + .filename("file1.txt") + .status("added") + .additions(103) + .deletions(21) + .changes(124) + .rawUrl( + URI.create( + "https://github.com/octocat/Hello-World/raw/6dcb09b5b57875f334f61aebed695e2e4193db5e/file1.txt")) + .blobUrl( + URI.create( + "https://github.com/octocat/Hello-World/blob/6dcb09b5b57875f334f61aebed695e2e4193db5e/file1.txt")) + .patch("@@ -132,7 +132,7 @@ module Test @@ -1000,7 +1000,7 @@ module Test") + .contentsUrl( + URI.create( + "https://api.github.com/repos/octocat/Hello-World/contents/file1.txt?ref=6dcb09b5b57875f334f61aebed695e2e4193db5e")) + .sha("bbcd538c8e72b8c175046e27cc8f907076331401") + .build(); + FileItem file2 = + ImmutableFileItem.builder() + .filename("file2.txt") + .status("modified") + .additions(103) + .deletions(21) + .changes(124) + .rawUrl( + URI.create( + "https://github.com/octocat/Hello-World/raw/6dcb09b5b57875f334f61aebed695e2e4193db5e/file2.txt")) + .blobUrl( + URI.create( + "https://github.com/octocat/Hello-World/blob/6dcb09b5b57875f334f61aebed695e2e4193db5e/file2.txt")) + .patch("@@ -132,7 +132,7 @@ module Test @@ -1000,7 +1000,7 @@ module Test") + .contentsUrl( + URI.create( + "https://api.github.com/repos/octocat/Hello-World/contents/file2.txt?ref=6dcb09b5b57875f334f61aebed695e2e4193db5e")) + .sha("bbcd538c8e72b8c175046e27cc8f907076331401") + .build(); + List expectedFiles = List.of(file1, file2); + final String expectedBody = github.json().toJsonUnchecked(expectedFiles); + + final String pageLink = + "; rel=\"first\""; + + final HttpResponse firstPageResponse = createMockResponse(pageLink, expectedBody); + + when(mockGithub.request( + format(PR_CHANGED_FILES_TEMPLATE + "?per_page=30", "owner", "repo", "1"))) + .thenReturn(completedFuture(firstPageResponse)); + + when(mockGithub.json()).thenReturn(github.json()); + + final PullRequestClient pullRequestClient = + PullRequestClient.create(mockGithub, "owner", "repo"); + + final Iterable> pageIterator = () -> pullRequestClient.changedFiles(1L); + List actualFiles = Async.streamFromPaginatingIterable(pageIterator).collect(toList()); + assertEquals(actualFiles.size(), expectedFiles.size()); + assertEquals(actualFiles.get(0).filename(), expectedFiles.get(0).filename()); + assertEquals(actualFiles.get(1).filename(), expectedFiles.get(1).filename()); + } + + @Test + public void testListComments() throws Throwable { + final String expectedBody = "[" + getFixture("pull_request_review_comment_reply.json") + "]"; + + final String pageLink = + ";" + + " rel=\"first\""; + + final HttpResponse firstPageResponse = createMockResponse(pageLink, expectedBody); + + when(mockGithub.request("/repos/owner/repo/pulls/1/comments?per_page=30")) + .thenReturn(completedFuture(firstPageResponse)); + + when(mockGithub.json()).thenReturn(github.json()); + + final PullRequestClient pullRequestClient = + PullRequestClient.create(mockGithub, "owner", "repo"); + + final Iterable> pageIterator = () -> pullRequestClient.listComments(1L); + List comments = Async.streamFromPaginatingIterable(pageIterator).collect(toList()); + + assertEquals(1, comments.size()); + assertThat(comments.get(0).body(), is("Great stuff!")); + assertThat(comments.get(0).id(), is(10L)); + assertThat(comments.get(0).user().login(), is("octocat")); + } + + @Test + public void testListReviewComments() throws Throwable { + final String expectedBody = "[" + getFixture("pull_request_review_comment_reply.json") + "]"; + + final String pageLink = + ";" + + " rel=\"first\""; + + final HttpResponse firstPageResponse = createMockResponse(pageLink, expectedBody); + + when(mockGithub.request("/repos/owner/repo/pulls/1/reviews/123/comments?per_page=30")) + .thenReturn(completedFuture(firstPageResponse)); + + when(mockGithub.json()).thenReturn(github.json()); + + final PullRequestClient pullRequestClient = + PullRequestClient.create(mockGithub, "owner", "repo"); + + final Iterable> pageIterator = + () -> pullRequestClient.listReviewComments(1L, 123L); + List comments = Async.streamFromPaginatingIterable(pageIterator).collect(toList()); + + assertEquals(1, comments.size()); + assertThat(comments.get(0).body(), is("Great stuff!")); + assertThat(comments.get(0).id(), is(10L)); + assertThat(comments.get(0).user().login(), is("octocat")); + } + + @Test + public void listCommitsWithoutSpecifyingPages() throws Exception { + // Given + final int COMMIT_PER_PAGE = 30; + + final String firstPageLink = + "; rel=\"next\"," + + " ; rel=\"last\""; + final String firstPageBody = + Resources.toString( + getResource(this.getClass(), "pull_request_commits_page1.json"), defaultCharset()); + final HttpResponse firstPageResponse = createMockResponse(firstPageLink, firstPageBody); + + when(mockGithub.request("/repos/owner/repo/pulls/1/commits")) + .thenReturn(completedFuture(firstPageResponse)); + + final PullRequestClient pullRequestClient = + PullRequestClient.create(mockGithub, "owner", "repo"); + + // When + final List commits = pullRequestClient.listCommits(1L).get(); + + // Then + assertThat(commits.size(), is(COMMIT_PER_PAGE)); + assertThat( + commits.get(COMMIT_PER_PAGE - 1).commit().tree().sha(), + is("219cb4c1ffada21259876d390df1a85767481617")); + } + + @Test + public void listCommitsSpecifyingPages() throws Exception { + // Given + final int COMMIT_PER_PAGE = 30; + + final String firstPageLink = + String.format( + "<%s/repos/owner/repo/pulls/1/commits?page=2&per_page=30>; rel=\"next\"," + + " <%s/repos/owner/repo/pulls/1/commits?page=3&per_page=30>; rel=\"last\"", + MOCK_GITHUB_URI, MOCK_GITHUB_URI); + final String firstPageBody = + Resources.toString( + getResource(this.getClass(), "pull_request_commits_page1.json"), defaultCharset()); + final HttpResponse firstPageResponse = createMockResponse(firstPageLink, firstPageBody); + + final String secondPageLink = + String.format( + "<%s/repos/owner/repo/pulls/1/commits?page=1&per_page=30>; rel=\"prev\"," + + " <%s/repos/owner/repo/pulls/1/commits?page=3&per_page=30>; rel=\"next\"," + + " <%s/repos/owner/repo/pulls/1/commits?page=3&per_page=30>; rel=\"last\"," + + " <%s/repos/owner/repo/pulls/1/commits?page=1&per_page=30>; rel=\"first\"", + MOCK_GITHUB_URI, MOCK_GITHUB_URI, MOCK_GITHUB_URI, MOCK_GITHUB_URI); + final String secondPageBody = + Resources.toString( + getResource(this.getClass(), "pull_request_commits_page2.json"), defaultCharset()); + final HttpResponse secondPageResponse = createMockResponse(secondPageLink, secondPageBody); + + final String thirdPageLink = + String.format( + "<%s/repos/owner/repo/pulls/1/commits?page=2&per_page=30>; rel=\"prev\"," + + " <%s/repos/owner/repo/pulls/1/commits?page=1&per_page=30>; rel=\"first\"", + MOCK_GITHUB_URI, MOCK_GITHUB_URI); + final String thirdPageBody = + Resources.toString( + getResource(this.getClass(), "pull_request_commits_page3.json"), defaultCharset()); + final HttpResponse thirdPageResponse = createMockResponse(thirdPageLink, thirdPageBody); + + when(mockGithub.urlFor("")).thenReturn(MOCK_GITHUB_URI.toString()); + when(mockGithub.json()).thenReturn(Json.create()); + when(mockGithub.request("/repos/owner/repo/pulls/1/commits?per_page=30")) + .thenReturn(completedFuture(firstPageResponse)); + when(mockGithub.request("/repos/owner/repo/pulls/1/commits?page=1&per_page=30")) + .thenReturn(completedFuture(firstPageResponse)); + when(mockGithub.request("/repos/owner/repo/pulls/1/commits?page=2&per_page=30")) + .thenReturn(completedFuture(secondPageResponse)); + when(mockGithub.request("/repos/owner/repo/pulls/1/commits?page=3&per_page=30")) + .thenReturn(completedFuture(thirdPageResponse)); + + final PullRequestClient pullRequestClient = + PullRequestClient.create(mockGithub, "owner", "repo"); + + // When + final Iterable> pageIterator = + () -> pullRequestClient.listCommits(1L, 30); + final List commits = + Async.streamFromPaginatingIterable(pageIterator).collect(toList()); + + // Then + assertThat(commits.size(), is(COMMIT_PER_PAGE * 3)); + assertThat( + commits.get(COMMIT_PER_PAGE - 1).commit().tree().sha(), + is("219cb4c1ffada21259876d390df1a85767481617")); + } } diff --git a/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java b/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java index bd8b7ace..fab85818 100644 --- a/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java @@ -29,7 +29,8 @@ import static com.spotify.github.v3.clients.GitHubClient.LIST_PR_TYPE_REFERENCE; import static com.spotify.github.v3.clients.GitHubClient.LIST_REPOSITORY; import static com.spotify.github.v3.clients.GitHubClient.LIST_REPOSITORY_INVITATION; -import static com.spotify.github.v3.clients.MockHelper.createMockResponse; +import static com.spotify.github.MockHelper.createMockHttpResponse; +import static com.spotify.github.MockHelper.createMockResponse; import static com.spotify.github.v3.clients.RepositoryClient.STATUS_URI_TEMPLATE; import static java.lang.String.format; import static java.nio.charset.Charset.defaultCharset; @@ -49,6 +50,7 @@ import com.google.common.io.Resources; import com.spotify.github.async.Async; import com.spotify.github.async.AsyncPage; +import com.spotify.github.http.HttpResponse; import com.spotify.github.jackson.Json; import com.spotify.github.v3.comment.Comment; import com.spotify.github.v3.prs.PullRequestItem; @@ -71,15 +73,11 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; -import okhttp3.MediaType; -import okhttp3.Protocol; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -122,7 +120,10 @@ public void getRepository() throws Exception { public void updateRepository() throws Exception { final CompletableFuture fixture = completedFuture(json.fromJson(getFixture("repository_get.json"), Repository.class)); - when(github.patch(eq("/repos/someowner/somerepo"), eq("{\"allow_auto_merge\":true}"), eq(Repository.class))) + when(github.patch( + eq("/repos/someowner/somerepo"), + eq("{\"allow_auto_merge\":true}"), + eq(Repository.class))) .thenReturn(fixture); RepositoryUpdate request = ImmutableRepositoryUpdate.builder().allowAutoMerge(Optional.of(true)).build(); @@ -150,9 +151,9 @@ public void listOrganizationRepositories() throws Exception { public void listAuthenticatedUserRepositories() throws Exception { final String pageLink = "; rel=\"first\""; final String pageBody = getFixture("list_of_repos_for_authenticated_user.json"); - final Response pageResponse = createMockResponse(pageLink, pageBody); + final HttpResponse pageResponse = createMockResponse(pageLink, pageBody); - when(github.request("/user/repos")).thenReturn(completedFuture(pageResponse)); + when(github.request("/user/repos?per_page=30")).thenReturn(completedFuture(pageResponse)); final Iterable> pageIterator = () -> @@ -167,8 +168,8 @@ public void listAuthenticatedUserRepositories() throws Exception { @Test public void isCollaborator() throws Exception { - final Response response = mock(Response.class); - when(response.code()).thenReturn(204); + final HttpResponse response = mock(HttpResponse.class); + when(response.statusCode()).thenReturn(204); when(github.request("/repos/someowner/somerepo/collaborators/user")) .thenReturn(completedFuture(response)); boolean isCollaborator = repoClient.isCollaborator("user").get(); @@ -177,8 +178,8 @@ public void isCollaborator() throws Exception { @Test public void isNotCollaborator() throws Exception { - final Response response = mock(Response.class); - when(response.code()).thenReturn(404); + final HttpResponse response = mock(HttpResponse.class); + when(response.statusCode()).thenReturn(404); when(github.request("/repos/someowner/somerepo/collaborators/user")) .thenReturn(completedFuture(response)); boolean isCollaborator = repoClient.isCollaborator("user").get(); @@ -187,7 +188,7 @@ public void isNotCollaborator() throws Exception { @Test public void addCollaborator() throws Exception { - final Response response = createMockResponse("", getFixture("repository_invitation.json")); + final HttpResponse response = createMockResponse("", getFixture("repository_invitation.json")); when(github.put("/repos/someowner/somerepo/collaborators/user", "{\"permission\":\"pull\"}")) .thenReturn(completedFuture(response)); @@ -207,8 +208,8 @@ public void addCollaborator() throws Exception { @Test public void addCollaboratorUserExists() throws Exception { - final Response response = mock(Response.class); - when(response.code()).thenReturn(204); + final HttpResponse response = mock(HttpResponse.class); + when(response.statusCode()).thenReturn(204); when(github.put("/repos/someowner/somerepo/collaborators/user", "{\"permission\":\"pull\"}")) .thenReturn(completedFuture(response)); @@ -220,7 +221,7 @@ public void addCollaboratorUserExists() throws Exception { @Test public void removeCollaborator() throws Exception { - CompletableFuture response = completedFuture(mock(Response.class)); + CompletableFuture response = completedFuture(mock(HttpResponse.class)); final ArgumentCaptor capture = ArgumentCaptor.forClass(String.class); when(github.delete(capture.capture())).thenReturn(response); @@ -232,7 +233,7 @@ public void removeCollaborator() throws Exception { @Test public void removeInvite() throws Exception { - CompletableFuture response = completedFuture(mock(Response.class)); + CompletableFuture response = completedFuture(mock(HttpResponse.class)); final ArgumentCaptor capture = ArgumentCaptor.forClass(String.class); when(github.delete(capture.capture())).thenReturn(response); @@ -285,7 +286,7 @@ public void listPullRequestsForCommit() throws Exception { .thenReturn(fixture); final List prs = repoClient.listPullRequestsForCommit("thesha").get(); assertThat(prs.size(), is(1)); - assertThat(prs.get(0).number(), is(1347)); + assertThat(prs.get(0).number(), is(1347L)); } @Test @@ -514,10 +515,10 @@ public void listBranches() throws Exception { @Test void listAllBranches() throws Exception { final String link = - "; rel=\"last\""; - final Response response = createMockResponse(link, getFixture("list_branches.json")); + "; rel=\"last\""; + final HttpResponse response = createMockResponse(link, getFixture("list_branches.json")); - when(github.request("/repos/someowner/somerepo/branches")) + when(github.request("/repos/someowner/somerepo/branches?per_page=30")) .thenReturn(completedFuture(response)); final List branches = Async.streamFromPaginatingIterable(repoClient::listAllBranches) @@ -539,7 +540,7 @@ public void testCommentCreated() throws IOException { .thenReturn(fixture); final Comment comment = repoClient.createComment("someweirdsha", "Me too").join(); - assertThat(comment.id(), is(123)); + assertThat(comment.id(), is(123L)); assertThat(comment.commitId().get(), is("6dcb09b5b57875f334f61aebed695e2e4193db5e")); } @@ -551,7 +552,7 @@ public void getComment() throws IOException { .thenReturn(fixture); final Comment comment = repoClient.getComment(123).join(); - assertThat(comment.id(), is(123)); + assertThat(comment.id(), is(123L)); assertThat(comment.commitId().get(), is("6dcb09b5b57875f334f61aebed695e2e4193db5e")); } @@ -561,25 +562,25 @@ public void testStatusesPaginationForeach() throws Exception { "; rel=\"next\", ; rel=\"last\""; final String firstPageBody = loadFixture("clients/statuses_page1.json"); - final Response firstPageResponse = createMockResponse(firstPageLink, firstPageBody); + final HttpResponse firstPageResponse = createMockResponse(firstPageLink, firstPageBody); final String lastPageLink = "; rel=\"first\", ; rel=\"prev\""; final String lastPageBody = loadFixture("clients/statuses_page2.json"); - final Response lastPageResponse = createMockResponse(lastPageLink, lastPageBody); + final HttpResponse lastPageResponse = createMockResponse(lastPageLink, lastPageBody); when(github.urlFor("")).thenReturn("https://github.com/api/v3"); when(github.request( format( - STATUS_URI_TEMPLATE, + STATUS_URI_TEMPLATE + "?per_page=30", "someowner", "somerepo", "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e"))) .thenReturn(completedFuture(firstPageResponse)); when(github.request( format( - STATUS_URI_TEMPLATE + "?page=2", + STATUS_URI_TEMPLATE + "?page=2&per_page=30", "someowner", "somerepo", "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e"))) @@ -597,17 +598,13 @@ public void testStatusesPaginationForeach() throws Exception { @Test public void merge() throws IOException { - CompletableFuture okResponse = + CompletableFuture okResponse = completedFuture( - new Response.Builder() - .request(new Request.Builder().url("http://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(201) - .body( - ResponseBody.create( - MediaType.get("application/json"), getFixture("merge_commit_item.json"))) - .build()); + createMockHttpResponse( + "http://example.com/whatever", + 201, + getFixture("merge_commit_item.json"), + Map.of())); final String expectedRequestBody = json.toJsonUnchecked( ImmutableMap.of( @@ -624,17 +621,10 @@ public void merge() throws IOException { @Test public void createFork() throws IOException { - CompletableFuture okResponse = + CompletableFuture okResponse = completedFuture( - new Response.Builder() - .request(new Request.Builder().url("http://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(202) - .body( - ResponseBody.create( - MediaType.get("application/json"), getFixture("fork_create_item.json"))) - .build()); + createMockHttpResponse( + "http://example.com/whatever", 202, getFixture("fork_create_item.json"), Map.of())); final String expectedRequestBody = json.toJsonUnchecked(ImmutableMap.of()); when(github.post("/repos/someowner/somerepo/forks", expectedRequestBody)) .thenReturn(okResponse); @@ -645,14 +635,8 @@ public void createFork() throws IOException { @Test public void mergeNoop() { - CompletableFuture okResponse = - completedFuture( - new Response.Builder() - .request(new Request.Builder().url("http://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(204) // No Content - .build()); + CompletableFuture okResponse = + completedFuture(createMockHttpResponse("http://example.com/whatever", 204, null, Map.of())); when(github.post(any(), any())).thenReturn(okResponse); final Optional maybeCommit = repoClient.merge("basebranch", "headbranch").join(); assertThat(maybeCommit, is(Optional.empty())); @@ -660,18 +644,13 @@ public void mergeNoop() { @Test public void shouldDownloadTarball() throws Exception { - CompletableFuture fixture = + CompletableFuture fixture = completedFuture( - new Response.Builder() - .request(new Request.Builder().url("https://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(200) - .body( - ResponseBody.create( - "some bytes".getBytes(StandardCharsets.UTF_8), - MediaType.get("application/gzip"))) - .build()); + createMockHttpResponse( + "http://example.com/whatever", + 200, + "some bytes", + Map.of())); when(github.request("/repos/someowner/somerepo/tarball/")).thenReturn(fixture); try (InputStream response = repoClient.downloadTarball().get().orElseThrow()) { @@ -682,18 +661,13 @@ public void shouldDownloadTarball() throws Exception { @Test public void shouldDownloadZipball() throws Exception { - CompletableFuture fixture = + CompletableFuture fixture = completedFuture( - new Response.Builder() - .request(new Request.Builder().url("https://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(200) - .body( - ResponseBody.create( - "some bytes".getBytes(StandardCharsets.UTF_8), - MediaType.get("application/gzip"))) - .build()); + createMockHttpResponse( + "http://example.com/whatever", + 200, + "some bytes", + Map.of())); when(github.request("/repos/someowner/somerepo/zipball/")).thenReturn(fixture); try (InputStream response = repoClient.downloadZipball().get().orElseThrow()) { @@ -704,14 +678,8 @@ public void shouldDownloadZipball() throws Exception { @Test public void shouldReturnEmptyOptionalWhenResponseBodyNotPresent() throws Exception { - CompletableFuture fixture = - completedFuture( - new Response.Builder() - .request(new Request.Builder().url("https://example.com/whatever").build()) - .protocol(Protocol.HTTP_1_1) - .message("") - .code(204) // No Content - .build()); + CompletableFuture fixture = + completedFuture(createMockHttpResponse("http://example.com/whatever", 204, null, Map.of())); when(github.request("/repos/someowner/somerepo/zipball/master")).thenReturn(fixture); Optional response = repoClient.downloadZipball("master").get(); @@ -720,23 +688,27 @@ public void shouldReturnEmptyOptionalWhenResponseBodyNotPresent() throws Excepti @Test public void shouldReturnEmptyResponseWhenRepositoryDispatchEndpointTriggered() throws Exception { - final Response response = mock(Response.class); - when(response.code()).thenReturn(204); + final HttpResponse response = mock(HttpResponse.class); + when(response.statusCode()).thenReturn(204); ObjectMapper mapper = new ObjectMapper(); ObjectNode clientPayload = mapper.createObjectNode(); - clientPayload.put("my-custom-true-property","true"); + clientPayload.put("my-custom-true-property", "true"); clientPayload.put("my-custom-false-property", "false"); - RepositoryDispatch repositoryDispatchRequest = ImmutableRepositoryDispatch.builder() - .eventType("my-custom-event") - .clientPayload(clientPayload) - .build(); + RepositoryDispatch repositoryDispatchRequest = + ImmutableRepositoryDispatch.builder() + .eventType("my-custom-event") + .clientPayload(clientPayload) + .build(); - when(github.post("/repos/someowner/somerepo/dispatches", json.toJsonUnchecked(repositoryDispatchRequest))).thenReturn(completedFuture(response)); + when(github.post( + "/repos/someowner/somerepo/dispatches", + json.toJsonUnchecked(repositoryDispatchRequest))) + .thenReturn(completedFuture(response)); - boolean repoDispatchResult = repoClient.createRepositoryDispatchEvent(repositoryDispatchRequest).get(); + boolean repoDispatchResult = + repoClient.createRepositoryDispatchEvent(repositoryDispatchRequest).get(); assertTrue(repoDispatchResult); } - } diff --git a/src/test/java/com/spotify/github/v3/clients/TeamClientTest.java b/src/test/java/com/spotify/github/v3/clients/TeamClientTest.java index c9240eb9..457c16ed 100644 --- a/src/test/java/com/spotify/github/v3/clients/TeamClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/TeamClientTest.java @@ -21,10 +21,11 @@ package com.spotify.github.v3.clients; import static com.google.common.io.Resources.getResource; +import static com.spotify.github.MockHelper.createMockHttpResponse; import static com.spotify.github.v3.clients.GitHubClient.LIST_PENDING_TEAM_INVITATIONS; import static com.spotify.github.v3.clients.GitHubClient.LIST_TEAMS; import static com.spotify.github.v3.clients.GitHubClient.LIST_TEAM_MEMBERS; -import static com.spotify.github.v3.clients.MockHelper.createMockResponse; +import static com.spotify.github.MockHelper.createMockResponse; import static java.nio.charset.Charset.defaultCharset; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.stream.Collectors.toList; @@ -37,6 +38,7 @@ import com.google.common.io.Resources; import com.spotify.github.async.Async; import com.spotify.github.async.AsyncPage; +import com.spotify.github.http.HttpResponse; import com.spotify.github.jackson.Json; import com.spotify.github.v3.Team; import com.spotify.github.v3.User; @@ -47,8 +49,9 @@ import com.spotify.github.v3.orgs.requests.TeamUpdate; import java.io.IOException; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; -import okhttp3.Response; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -97,7 +100,7 @@ public void listTeams() throws Exception { @Test public void deleteTeam() throws Exception { - final CompletableFuture response = completedFuture(mock(Response.class)); + final CompletableFuture response = completedFuture(mock(HttpResponse.class)); final ArgumentCaptor capture = ArgumentCaptor.forClass(String.class); when(github.delete(capture.capture())).thenReturn(response); @@ -134,7 +137,10 @@ public void updateTeam() throws Exception { assertThat(actualResponse.get().name(), is("Justice League2")); verify(github, times(1)) - .patch(eq("/orgs/github/teams/justice-league"), eq("{\"name\":\"Justice League2\"}"), eq(Team.class)); + .patch( + eq("/orgs/github/teams/justice-league"), + eq("{\"name\":\"Justice League2\"}"), + eq(Team.class)); } @Test @@ -164,22 +170,24 @@ public void listTeamMembers() throws Exception { @Test public void listTeamMembersPaged() throws Exception { final String firstPageLink = - "; rel=\"next\", ; rel=\"last\""; + "; rel=\"next\", ; rel=\"last\""; final String firstPageBody = - Resources.toString(getResource(this.getClass(), "list_members_page1.json"), defaultCharset()); - final Response firstPageResponse = createMockResponse(firstPageLink, firstPageBody); + Resources.toString( + getResource(this.getClass(), "list_members_page1.json"), defaultCharset()); + final HttpResponse firstPageResponse = createMockResponse(firstPageLink, firstPageBody); final String lastPageLink = - "; rel=\"first\", ; rel=\"prev\""; + "; rel=\"first\", ; rel=\"prev\""; final String lastPageBody = - Resources.toString(getResource(this.getClass(), "list_members_page2.json"), defaultCharset()); + Resources.toString( + getResource(this.getClass(), "list_members_page2.json"), defaultCharset()); - final Response lastPageResponse = createMockResponse(lastPageLink, lastPageBody); + final HttpResponse lastPageResponse = createMockResponse(lastPageLink, lastPageBody); when(github.request(endsWith("/orgs/github/teams/1/members?per_page=1"))) - .thenReturn(completedFuture(firstPageResponse)); - when(github.request(endsWith("/orgs/github/teams/1/members?page=2"))) - .thenReturn(completedFuture(lastPageResponse)); + .thenReturn(completedFuture(firstPageResponse)); + when(github.request(endsWith("/orgs/github/teams/1/members?page=2&per_page=1"))) + .thenReturn(completedFuture(lastPageResponse)); final Iterable> pageIterator = () -> teamClient.listTeamMembers("1", 1); final List users = Async.streamFromPaginatingIterable(pageIterator).collect(toList()); @@ -206,7 +214,7 @@ public void updateMembership() throws Exception { @Test public void deleteMembership() throws Exception { - final CompletableFuture response = completedFuture(mock(Response.class)); + final CompletableFuture response = completedFuture(mock(HttpResponse.class)); final ArgumentCaptor capture = ArgumentCaptor.forClass(String.class); when(github.delete(capture.capture())).thenReturn(response); @@ -228,4 +236,19 @@ public void listPendingTeamInvitations() throws Exception { assertThat(pendingInvitations.get(1).id(), is(2)); assertThat(pendingInvitations.size(), is(2)); } + + @Test + void updateTeamPermissions() { + String apiUrl = "/orgs/github/teams/cat-squad/repos/github/octocat"; + HttpResponse response = createMockHttpResponse(apiUrl, 204, "", Map.of()); + when(github.put(eq(apiUrl), any())).thenReturn(completedFuture(response)); + + teamClient.updateTeamPermissions("cat-squad", "octocat", "pull").join(); + + verify(github, times(1)) + .put( + eq(apiUrl), + eq( + "{\"org\":\"github\",\"repo\":\"octocat\",\"team_slug\":\"cat-squad\",\"permission\":\"pull\"}")); + } } diff --git a/src/test/java/com/spotify/github/v3/clients/UserClientTest.java b/src/test/java/com/spotify/github/v3/clients/UserClientTest.java index ce8e7259..50fcd3b9 100644 --- a/src/test/java/com/spotify/github/v3/clients/UserClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/UserClientTest.java @@ -31,6 +31,7 @@ import static org.mockito.Mockito.when; import com.google.common.io.Resources; +import com.spotify.github.http.HttpResponse; import com.spotify.github.jackson.Json; import com.spotify.github.v3.checks.Installation; import com.spotify.github.v3.user.requests.ImmutableSuspensionReason; @@ -62,8 +63,8 @@ public void setUp() { @Test public void testSuspendUserSuccess() throws Exception { - Response response = mock(Response.class); - when(response.code()).thenReturn(204); + HttpResponse response = mock(HttpResponse.class); + when(response.statusCode()).thenReturn(204); when(github.put(eq("/users/username/suspended"), any())).thenReturn(completedFuture(response)); final CompletableFuture result = userClient.suspendUser("username", ImmutableSuspensionReason.builder().reason("That's why").build()); assertTrue(result.get()); @@ -71,8 +72,8 @@ public void testSuspendUserSuccess() throws Exception { @Test public void testSuspendUserFailure() throws Exception { - Response response = mock(Response.class); - when(response.code()).thenReturn(403); + HttpResponse response = mock(HttpResponse.class); + when(response.statusCode()).thenReturn(403); when(github.put(eq("/users/username/suspended"), any())).thenReturn(completedFuture(response)); final CompletableFuture result = userClient.suspendUser("username", ImmutableSuspensionReason.builder().reason("That's why").build()); assertFalse(result.get()); @@ -80,8 +81,8 @@ public void testSuspendUserFailure() throws Exception { @Test public void testUnSuspendUserSuccess() throws Exception { - Response response = mock(Response.class); - when(response.code()).thenReturn(204); + HttpResponse response = mock(HttpResponse.class); + when(response.statusCode()).thenReturn(204); when(github.delete(eq("/users/username/suspended"), any())).thenReturn(completedFuture(response)); final CompletableFuture result = userClient.unSuspendUser("username", ImmutableSuspensionReason.builder().reason("That's why").build()); assertTrue(result.get()); @@ -89,8 +90,8 @@ public void testUnSuspendUserSuccess() throws Exception { @Test public void testUnSuspendUserFailure() throws Exception { - Response response = mock(Response.class); - when(response.code()).thenReturn(403); + HttpResponse response = mock(HttpResponse.class); + when(response.statusCode()).thenReturn(403); when(github.delete(eq("/users/username/suspended"), any())).thenReturn(completedFuture(response)); final CompletableFuture result = userClient.unSuspendUser("username", ImmutableSuspensionReason.builder().reason("That's why").build()); assertFalse(result.get()); diff --git a/src/test/java/com/spotify/github/v3/clients/WorkflowsClientTest.java b/src/test/java/com/spotify/github/v3/clients/WorkflowsClientTest.java new file mode 100644 index 00000000..3a51722a --- /dev/null +++ b/src/test/java/com/spotify/github/v3/clients/WorkflowsClientTest.java @@ -0,0 +1,97 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ + +package com.spotify.github.v3.clients; + +import com.google.common.io.Resources; +import com.spotify.github.jackson.Json; +import com.spotify.github.v3.workflows.WorkflowsRepositoryResponseList; +import com.spotify.github.v3.workflows.WorkflowsResponse; +import com.spotify.github.v3.workflows.WorkflowsState; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.concurrent.CompletableFuture; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.concurrent.CompletableFuture.completedFuture; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class WorkflowsClientTest { + + private static final String FIXTURES_PATH = "com/spotify/github/v3/workflows/"; + private GitHubClient github; + private WorkflowsClient workflowsClient; + private Json json; + + public static String loadResource(final String path) { + try { + return Resources.toString(Resources.getResource(path), UTF_8); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @BeforeEach + public void setUp() { + github = mock(GitHubClient.class); + workflowsClient = new WorkflowsClient(github, "someowner", "somerepo"); + json = Json.create(); + when(github.json()).thenReturn(json); + } + + @Test + public void getWorkflow() throws Exception { + final WorkflowsResponse workflowsResponse = + json.fromJson( + loadResource(FIXTURES_PATH + "workflows-get-workflow-response.json"), WorkflowsResponse.class); + final CompletableFuture fixtureResponse = completedFuture(workflowsResponse); + when(github.request(any(), eq(WorkflowsResponse.class), any())).thenReturn(fixtureResponse); + + final CompletableFuture actualResponse = + workflowsClient.getWorkflow(161335); + + assertThat(actualResponse.get().id(), is(161335)); + assertThat(actualResponse.get().state(), is(WorkflowsState.active)); + } + + @Test + public void listWorkflows() throws Exception { + final WorkflowsRepositoryResponseList workflowsListResponse = + json.fromJson( + loadResource(FIXTURES_PATH + "workflows-list-workflows-response.json"), WorkflowsRepositoryResponseList.class); + final CompletableFuture fixtureResponse = completedFuture(workflowsListResponse); + when(github.request(any(), eq(WorkflowsRepositoryResponseList.class), any())).thenReturn(fixtureResponse); + + final CompletableFuture actualResponse = + workflowsClient.listWorkflows(); + + assertThat(actualResponse.get().totalCount(), is(2)); + assertThat(actualResponse.get().workflows().get(0).name(), is("CI")); + assertThat(actualResponse.get().workflows().get(1).name(), is("Linter")); + } +} \ No newline at end of file diff --git a/src/test/java/com/spotify/github/v3/comment/CommentReactionContentTest.java b/src/test/java/com/spotify/github/v3/comment/CommentReactionContentTest.java new file mode 100644 index 00000000..cade32ba --- /dev/null +++ b/src/test/java/com/spotify/github/v3/comment/CommentReactionContentTest.java @@ -0,0 +1,40 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * -/-/- + */ +package com.spotify.github.v3.comment; + +import static org.junit.jupiter.api.Assertions.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +class CommentReactionContentTest { + @ParameterizedTest + @EnumSource(CommentReactionContent.class) + public void testDeserialize(CommentReactionContent reaction) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + + String json = "\"" + reaction.toString() + "\""; + + CommentReactionContent content = mapper.readValue(json, CommentReactionContent.class); + + assertEquals(reaction, content); + } +} diff --git a/src/test/java/com/spotify/github/v3/prs/PullRequestTest.java b/src/test/java/com/spotify/github/v3/prs/PullRequestTest.java index 31e47543..5cedad6b 100644 --- a/src/test/java/com/spotify/github/v3/prs/PullRequestTest.java +++ b/src/test/java/com/spotify/github/v3/prs/PullRequestTest.java @@ -24,6 +24,8 @@ import static java.nio.charset.Charset.defaultCharset; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import com.google.common.io.Resources; import com.spotify.github.jackson.Json; @@ -38,6 +40,8 @@ public void testDeserializationPr() throws IOException { String fixture = Resources.toString(getResource(this.getClass(), "pull_request.json"), defaultCharset()); final PullRequest pr = Json.create().fromJson(fixture, PullRequest.class); + + assertThat(pr.id(), is(1L)); assertThat(pr.nodeId(), is("MDExOlB1bGxSZXF1ZXN0NDI3NDI0Nw==")); assertThat(pr.mergeCommitSha().get(), is("e5bd3914e2e596debea16f433f57875b5b90bcd6")); assertThat(pr.merged(), is(false)); @@ -47,6 +51,23 @@ public void testDeserializationPr() throws IOException { assertThat(pr.deletions(), is(3)); assertThat(pr.changedFiles(), is(5)); assertThat(pr.draft(), is(Optional.of(false))); + assertThat(pr.labels().size(),is(1)); + assertThat(pr.labels().get(0).name(),is("bug")); + assertThat(pr.labels().get(0).id(),is(42L)); + assertThat(pr.labels().get(0).color(),is("ff0000")); + } + + @Test + public void testDeserializationPrWithLargeId() throws IOException { + String fixture = + Resources.toString(getResource(this.getClass(), "pull_request_long_id.json"), defaultCharset()); + final PullRequest pr = Json.create().fromJson(fixture, PullRequest.class); + + assertThat(pr.id(), is(2459198527L)); + assertThat(pr.head().sha(), is("f74c7f420282f584acd2fb5964202e5b525c3ab8")); + assertThat(pr.merged(), is(false)); + assertThat(pr.mergeable().get(), is(false)); + assertThat(pr.draft(), is(Optional.of(true))); } @Test @@ -66,6 +87,36 @@ public void testSerializationMergeParams() throws IOException { assertThat(params.mergeMethod(), is(MergeMethod.merge)); } + @Test + public void testSerializationAutoMergeDisabled() throws IOException { + String fixture = + Resources.toString(getResource(this.getClass(), "pull_request_automerge_disabled.json"), defaultCharset()); + final PullRequest pr = Json.create().fromJson(fixture, PullRequest.class); + + assertThat(pr.id(), is(2439836648L)); + assertThat(pr.head().sha(), is("881ef333d1ffc01869b666f13d3b37d7af92b9a2")); + assertThat(pr.merged(), is(false)); + assertThat(pr.mergeable().get(), is(true)); + assertThat(pr.draft(), is(Optional.of(true))); + assertNull(pr.autoMerge()); + } + + @Test + public void testSerializationAutoMergeEnabled() throws IOException { + String fixture = + Resources.toString(getResource(this.getClass(), "pull_request_automerge_enabled.json"), defaultCharset()); + final PullRequest pr = Json.create().fromJson(fixture, PullRequest.class); + + assertThat(pr.id(), is(2439836648L)); + assertThat(pr.head().sha(), is("881ef333d1ffc01869b666f13d3b37d7af92b9a2")); + assertThat(pr.merged(), is(false)); + assertThat(pr.mergeable().get(), is(true)); + assertThat(pr.draft(), is(Optional.of(false))); + assertNotNull(pr.autoMerge()); + assertThat(pr.autoMerge().enabledBy().login(), is("octocat")); + assertThat(pr.autoMerge().mergeMethod(), is("squash")); + } + @Test public void testDeserializationMergeParamsOmitsFields() throws IOException { final MergeParameters params = ImmutableMergeParameters.builder() diff --git a/src/test/java/com/spotify/github/v3/prs/ReviewTest.java b/src/test/java/com/spotify/github/v3/prs/ReviewTest.java index db54fc29..cefe2a3a 100644 --- a/src/test/java/com/spotify/github/v3/prs/ReviewTest.java +++ b/src/test/java/com/spotify/github/v3/prs/ReviewTest.java @@ -41,6 +41,20 @@ public void testDeserialization() throws IOException { Json.create().fromJson(fixture, Review.class); assertThat(review.state(), is(ReviewState.APPROVED)); assertThat(review.commitId(), is("ecdd80bb57125d7ba9641ffaa4d7d2c19d3f3091")); - assertThat(review.id(), is(80)); + assertThat(review.id(), is(80L)); } + + @Test + public void testDeserializationWithLargeId() throws IOException { + String fixture = + Resources.toString( + getResource(this.getClass(), "review_long_id.json"), + defaultCharset()); + final Review review = + Json.create().fromJson(fixture, Review.class); + assertThat(review.state(), is(ReviewState.APPROVED)); + assertThat(review.commitId(), is("ecdd80bb57125d7ba9641ffaa4d7d2c19d3f3091")); + assertThat(review.id(), is(2459198580L)); + } + } \ No newline at end of file diff --git a/src/test/java/com/spotify/github/v3/search/SearchTest.java b/src/test/java/com/spotify/github/v3/search/SearchTest.java index ab04989c..b4678875 100644 --- a/src/test/java/com/spotify/github/v3/search/SearchTest.java +++ b/src/test/java/com/spotify/github/v3/search/SearchTest.java @@ -41,8 +41,8 @@ public static final void assertSearchIssues(final SearchIssues search) { assertThat( issues.url(), is(URI.create("https://api.github.com/repos/batterseapower/pinyin-toolkit/issues/132"))); - assertThat(issues.number(), is(132)); - assertThat(issues.id(), is(35802)); + assertThat(issues.number(), is(132L)); + assertThat(issues.id(), is(35802L)); assertThat(issues.title(), is("Line Number Indexes Beyond 20 Not Displayed")); } @@ -54,4 +54,17 @@ public void testDeserialization() throws IOException { final SearchIssues search = Json.create().fromJson(fixture, SearchIssues.class); assertSearchIssues(search); } + + @Test + public void testDeserializationWithLargeIssueId() throws IOException { + final String fixture = + Resources.toString(getResource(this.getClass(), "issues-long-id.json"), defaultCharset()); + + final SearchIssues search = Json.create().fromJson(fixture, SearchIssues.class); + assertThat(search.items().size(), is(1)); + + final Issue issue = search.items().get(0); + assertThat(issue.id(), is(2592843837L)); + assertThat(issue.number(), is(5514L)); + } } diff --git a/src/test/resources/com/spotify/github/v3/activity/events/fixtures/issue_comment_event.json b/src/test/resources/com/spotify/github/v3/activity/events/fixtures/issue_comment_event.json index 6f6e7d89..650d4ce4 100644 --- a/src/test/resources/com/spotify/github/v3/activity/events/fixtures/issue_comment_event.json +++ b/src/test/resources/com/spotify/github/v3/activity/events/fixtures/issue_comment_event.json @@ -32,7 +32,9 @@ { "url": "https://api.github.com/repos/baxterthehacker/public-repo/labels/bug", "name": "bug", - "color": "fc2929" + "color": "fc2929", + "default": false, + "id": 208045946 } ], "state": "open", @@ -50,6 +52,7 @@ "html_url": "https://github.com/baxterthehacker/public-repo/issues/2#issuecomment-99262140", "issue_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/2", "id": 99262140, + "node_id": "asd123", "user": { "login": "baxterthehacker", "id": 6752317, diff --git a/src/test/resources/com/spotify/github/v3/activity/events/fixtures/merge_group_event.json b/src/test/resources/com/spotify/github/v3/activity/events/fixtures/merge_group_event.json new file mode 100644 index 00000000..531f706d --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/activity/events/fixtures/merge_group_event.json @@ -0,0 +1,116 @@ +{ + "action": "checks_requested", + "merge_group": { + "head_sha": "cd84187b3e9a3e8f5b5f5b5f5b5f5b5f5b5f5b5f", + "head_ref": "refs/heads/gh-readonly-queue/main/pr-123-cd84187b3e9a3e8f5b5f5b5f5b5f5b5f5b5f5b5f", + "base_sha": "9049f1265b7d61be4a8904a9a27120d2064dab3b", + "base_ref": "refs/heads/main" + }, + "repository": { + "id": 35129377, + "name": "public-repo", + "full_name": "baxterthehacker/public-repo", + "owner": { + "login": "baxterthehacker", + "id": 6752317, + "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/baxterthehacker", + "html_url": "https://github.com/baxterthehacker", + "followers_url": "https://api.github.com/users/baxterthehacker/followers", + "following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}", + "gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}", + "starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions", + "organizations_url": "https://api.github.com/users/baxterthehacker/orgs", + "repos_url": "https://api.github.com/users/baxterthehacker/repos", + "events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}", + "received_events_url": "https://api.github.com/users/baxterthehacker/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/baxterthehacker/public-repo", + "description": "", + "fork": false, + "url": "https://api.github.com/repos/baxterthehacker/public-repo", + "forks_url": "https://api.github.com/repos/baxterthehacker/public-repo/forks", + "keys_url": "https://api.github.com/repos/baxterthehacker/public-repo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/baxterthehacker/public-repo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/baxterthehacker/public-repo/teams", + "hooks_url": "https://api.github.com/repos/baxterthehacker/public-repo/hooks", + "issue_events_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/events{/number}", + "events_url": "https://api.github.com/repos/baxterthehacker/public-repo/events", + "assignees_url": "https://api.github.com/repos/baxterthehacker/public-repo/assignees{/user}", + "branches_url": "https://api.github.com/repos/baxterthehacker/public-repo/branches{/branch}", + "tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/tags", + "blobs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/baxterthehacker/public-repo/languages", + "stargazers_url": "https://api.github.com/repos/baxterthehacker/public-repo/stargazers", + "contributors_url": "https://api.github.com/repos/baxterthehacker/public-repo/contributors", + "subscribers_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscribers", + "subscription_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscription", + "commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/baxterthehacker/public-repo/contents/{+path}", + "compare_url": "https://api.github.com/repos/baxterthehacker/public-repo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/baxterthehacker/public-repo/merges", + "archive_url": "https://api.github.com/repos/baxterthehacker/public-repo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/baxterthehacker/public-repo/downloads", + "issues_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues{/number}", + "pulls_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/baxterthehacker/public-repo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/baxterthehacker/public-repo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/baxterthehacker/public-repo/labels{/name}", + "releases_url": "https://api.github.com/repos/baxterthehacker/public-repo/releases{/id}", + "deployments_url": "https://api.github.com/repos/baxterthehacker/public-repo/deployments", + "created_at": "2015-05-05T23:40:12Z", + "updated_at": "2016-08-15T17:19:01Z", + "pushed_at": "2016-10-03T23:37:43Z", + "git_url": "git://github.com/baxterthehacker/public-repo.git", + "ssh_url": "git@github.com:baxterthehacker/public-repo.git", + "clone_url": "https://github.com/baxterthehacker/public-repo.git", + "svn_url": "https://github.com/baxterthehacker/public-repo", + "homepage": null, + "size": 233, + "stargazers_count": 2, + "watchers_count": 2, + "language": null, + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 2, + "mirror_url": null, + "open_issues_count": 5, + "forks": 2, + "open_issues": 5, + "watchers": 2, + "default_branch": "master" + }, + "sender": { + "login": "baxterthehacker", + "id": 6752317, + "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/baxterthehacker", + "html_url": "https://github.com/baxterthehacker", + "followers_url": "https://api.github.com/users/baxterthehacker/followers", + "following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}", + "gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}", + "starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions", + "organizations_url": "https://api.github.com/users/baxterthehacker/orgs", + "repos_url": "https://api.github.com/users/baxterthehacker/repos", + "events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}", + "received_events_url": "https://api.github.com/users/baxterthehacker/received_events", + "type": "User", + "site_admin": false + } +} \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/activity/events/fixtures/pull_request_review_comment_event.json b/src/test/resources/com/spotify/github/v3/activity/events/fixtures/pull_request_review_comment_event.json index a89b6b54..7db9196d 100644 --- a/src/test/resources/com/spotify/github/v3/activity/events/fixtures/pull_request_review_comment_event.json +++ b/src/test/resources/com/spotify/github/v3/activity/events/fixtures/pull_request_review_comment_event.json @@ -3,12 +3,23 @@ "comment": { "url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/comments/29724692", "id": 29724692, + "node_id": "abc234", "diff_hunk": "@@ -1 +1 @@\n-# public-repo", "path": "README.md", "position": 1, - "original_position": 1, "commit_id": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c", "original_commit_id": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c", + "original_line": 1, + "original_position": 1, + "original_start_line": 1, + "line": 1, + "side": "RIGHT", + "start_line": 1, + "start_side": "RIGHT", + "author_association": "NONE", + "pull_request_review_id": 42, + "in_reply_to_id": 426899381, + "subject_type": "line", "user": { "login": "baxterthehacker", "id": 6752317, @@ -48,6 +59,7 @@ "pull_request": { "url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1", "id": 34778301, + "node_id": "abc123", "html_url": "https://github.com/baxterthehacker/public-repo/pull/1", "diff_url": "https://github.com/baxterthehacker/public-repo/pull/1.diff", "patch_url": "https://github.com/baxterthehacker/public-repo/pull/1.patch", diff --git a/src/test/resources/com/spotify/github/v3/clients/comment_created_long_id.json b/src/test/resources/com/spotify/github/v3/clients/comment_created_long_id.json new file mode 100644 index 00000000..1ddd888a --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/clients/comment_created_long_id.json @@ -0,0 +1,45 @@ +{ + "url": "https://api.github.com/repos/spotify/github-java-client/issues/comments/1958720937", + "html_url": "https://github.com/spotify/github-java-client/pull/180#issuecomment-1958720937", + "issue_url": "https://api.github.com/repos/spotify/github-java-client/issues/180", + "id": 2459198527, + "node_id": "IC_kwDODynaQc50v7Wp", + "user": { + "login": "vootelerotov", + "id": 1439555, + "node_id": "MDQ6VXNlcjE0Mzk1NTU=", + "avatar_url": "https://avatars.githubusercontent.com/u/1439555?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/vootelerotov", + "html_url": "https://github.com/vootelerotov", + "followers_url": "https://api.github.com/users/vootelerotov/followers", + "following_url": "https://api.github.com/users/vootelerotov/following{/other_user}", + "gists_url": "https://api.github.com/users/vootelerotov/gists{/gist_id}", + "starred_url": "https://api.github.com/users/vootelerotov/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/vootelerotov/subscriptions", + "organizations_url": "https://api.github.com/users/vootelerotov/orgs", + "repos_url": "https://api.github.com/users/vootelerotov/repos", + "events_url": "https://api.github.com/users/vootelerotov/events{/privacy}", + "received_events_url": "https://api.github.com/users/vootelerotov/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "created_at": "2024-02-22T05:19:44Z", + "updated_at": "2024-02-22T05:19:44Z", + "author_association": "CONTRIBUTOR", + "body": "Ran into this in the wild.", + "reactions": { + "url": "https://api.github.com/repos/spotify/github-java-client/issues/comments/1958720937/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "performed_via_github_app": null +} diff --git a/src/test/resources/com/spotify/github/v3/clients/pull_request_commits_page1.json b/src/test/resources/com/spotify/github/v3/clients/pull_request_commits_page1.json new file mode 100644 index 00000000..6f043338 --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/clients/pull_request_commits_page1.json @@ -0,0 +1,2422 @@ +[ + { + "sha": "443831b0008519c93a57f96fb45a455f8e1453d0", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjQ0MzgzMWIwMDA4NTE5YzkzYTU3Zjk2ZmI0NWE0NTVmOGUxNDUzZDA=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-11T18:32:31Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:01Z" + }, + "message": "STASH incomplete feature (no UI, some TODOs)", + "tree": { + "sha": "362e3e7da340b93600dfc03f42a5448b01603aa8", + "url": "https://api.github.com/repos/facebook/react/git/trees/362e3e7da340b93600dfc03f42a5448b01603aa8" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/443831b0008519c93a57f96fb45a455f8e1453d0", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UkACgkQWCcTbp05\ndTIJaw//fA9sw4IgzFBupPjSniwta+TMNubK6rLakXmX61gWYoKPRkQx0N1cK5k2\n0ohggmhLb7c75kjShLCYu1RTYHR1hN1xpahPjurvXMNXt908oBrzEoDR7XQg3NEO\n2yJ1d0QsCcPimzHztGkHnO1oD2S8XZ+NBwEpJxTNc+xAotkxS0dlS1nYyNsCnpRY\nozG9oyYMfaHyZOgrONl7wqwaBHS9RVvppiAiaRKy0p9eozf1hAUkPXRTIUbXg/fV\nGrOjrNvffe3CrI7quZDqzCcvfuL7CTrcw3+Gw0pRHcx/GtM25/9ewTScaR5B9CWB\nmd6gu2KMuP6/DfJWtBJ3zOuTTDvRRh8cds1BL4tPQuLn6g295HDNLgBB/4esCL3q\naR60UOuWS/L3JQeYWKS+JAJlm+cycDHpSbzznXSJpVbrGC0YseI1qZpgEMDwcwUX\n7aFfMSppPF4PkTqWvEuUnQdwtLhhm+yKFKkAPude4ZjSInIY/ioLhpcupb62C45K\nRVL4Ihj4Jzoorz5SFMgvTg12HLMho/fJcwNPWn2RZCG1i8xgjIP8Jgod5HzOhE7n\ngJjL7Gb+fjnSjMpASGf9Cqw7TWYLMD+H59VAk4ZOzlqxZ95P41ECw0GpST5uFBY8\nH7/bUkIf/M26xJzVv82nRApQsFgXDxa+bOuXUgURshZmVt3jOcU=\n=pF+Q\n-----END PGP SIGNATURE-----", + "payload": "tree 362e3e7da340b93600dfc03f42a5448b01603aa8\nparent 3f9205c3331b80f13a0376826d1ef859786c086b\nauthor eps1lon 1607711551 +0100\ncommitter eps1lon 1607985481 +0100\n\nSTASH incomplete feature (no UI, some TODOs)\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/443831b0008519c93a57f96fb45a455f8e1453d0", + "html_url": "https://github.com/facebook/react/commit/443831b0008519c93a57f96fb45a455f8e1453d0", + "comments_url": "https://api.github.com/repos/facebook/react/commits/443831b0008519c93a57f96fb45a455f8e1453d0/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "3f9205c3331b80f13a0376826d1ef859786c086b", + "url": "https://api.github.com/repos/facebook/react/commits/3f9205c3331b80f13a0376826d1ef859786c086b", + "html_url": "https://github.com/facebook/react/commit/3f9205c3331b80f13a0376826d1ef859786c086b" + } + ] + }, + { + "sha": "1a34269cb1fede931153172fdeaca034ccadcda2", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjFhMzQyNjljYjFmZWRlOTMxMTUzMTcyZmRlYWNhMDM0Y2NhZGNkYTI=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-11T20:04:55Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:01Z" + }, + "message": "Add UI", + "tree": { + "sha": "a7ba32a1d26bf21c20303716b53047afc2b19eb3", + "url": "https://api.github.com/repos/facebook/react/git/trees/a7ba32a1d26bf21c20303716b53047afc2b19eb3" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/1a34269cb1fede931153172fdeaca034ccadcda2", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UkACgkQWCcTbp05\ndTI7+Q/+Jjp/tDSFgbwa2wzhfnbnVDIurh2ICKUKnET1s44gA0Fkn1SJcm6atpI+\nISt4pVkcjoxGoF4jpYLK/PhY8IQrAzZhvIJ40gUC2NLutsPsb8ugREyMhYCIlCTP\nD0QBZMM7RG5p5u1T9E+c+K44sInOcnNxX7ioCeFK1nF2BsbNfkV9SUOZlelop9bh\n/qSyAIiOj9aqsx7d2Pu1LDdhjBXXunPxSNk11shAyO/OcxBAPqdZaHT+XGHj/FpB\n9Q3Pj4tjTr9ERRkchcWUsRPL8zxlimVwBcX6an1k7fCRywzkQWgxyyP9msQDTD0a\nu18hLoHpJfbyBgO5nuD1SCAKJfopgqpQt+/CyQjbqOjaNOBA0m9wUk8U5gVHxOoG\n/ZcMNDXra2DvVj5MYENuYtLUzLXJJ6AD8vu/K9FhZUfHy6Yk4Gfrq9Kidx/YSirS\nJoAO2jHYTb/Lyg3iNeEQgYkVaMhMsLAQWRx9B56PhGdMTbHDeQ3r85LqbORWNCku\npzlPEq4S41cYZYlV6XZr6/gBWNW+neGEIFBMw7N1UJ/6VJiDsG0QVUTvDFilrOCV\nXvRCdpPY40C0NiahVHyO06gojGPzbEhfjvnXoxmKe+Hs6RNJDqF/fRSqGl3py3r2\n5pRmGf5vgc6aldIPO8uw1J/vEHwL80hjiT7wcT8kYikiMkweUWI=\n=vEUV\n-----END PGP SIGNATURE-----", + "payload": "tree a7ba32a1d26bf21c20303716b53047afc2b19eb3\nparent 443831b0008519c93a57f96fb45a455f8e1453d0\nauthor eps1lon 1607717095 +0100\ncommitter eps1lon 1607985481 +0100\n\nAdd UI\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/1a34269cb1fede931153172fdeaca034ccadcda2", + "html_url": "https://github.com/facebook/react/commit/1a34269cb1fede931153172fdeaca034ccadcda2", + "comments_url": "https://api.github.com/repos/facebook/react/commits/1a34269cb1fede931153172fdeaca034ccadcda2/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "443831b0008519c93a57f96fb45a455f8e1453d0", + "url": "https://api.github.com/repos/facebook/react/commits/443831b0008519c93a57f96fb45a455f8e1453d0", + "html_url": "https://github.com/facebook/react/commit/443831b0008519c93a57f96fb45a455f8e1453d0" + } + ] + }, + { + "sha": "6cc7fdb8642f40c34d067f991dd01bf45149883e", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjZjYzdmZGI4NjQyZjQwYzM0ZDA2N2Y5OTFkZDAxYmY0NTE0OTg4M2U=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T17:04:07Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:01Z" + }, + "message": "Add view for errors/warnings in inspected element", + "tree": { + "sha": "c03f88d24809204587b25a676afc09f98ef23c38", + "url": "https://api.github.com/repos/facebook/react/git/trees/c03f88d24809204587b25a676afc09f98ef23c38" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/6cc7fdb8642f40c34d067f991dd01bf45149883e", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UkACgkQWCcTbp05\ndTKExw/9GErqES02exoefSLGYts3V7CCZzAtB4n0x+VbCufwWHynaKXt+ELo1UFg\nA15+TvAK0C4C/XCkzDdDKYQwGs/OpCSyJSNDjwzeOHVtonkPeR8Jp9eE2wioQQUE\nxCXNDVFRuJHQHEkcI4MbWVyOOJAQjSenesAojd1xEmIGgxGjPmYaULfCjJoKQung\ntBxzDEj6ngd0Sjb7U6SQpiSJQwG2JWSdBaI3HgBhV5Pq54pgnoCgv+nJb51I715e\nMOhbC3qWfs9OQyEO7cvsfcONrN6+20F3oq9gM7COaBFCee1g19hIDQGCCgzhkJzP\nz+UFarXTvaz+PHmTTrxyDVqh2M0tnu3wjQlyXK72f7XdCF8Yk92zSqEbKFqiiSsM\nTxQ5awFvae7K4Egv1gTiS3+p6CB+ReuN108sIwrHd1UT9yvEnLqu+1Xi6Z+sH855\nYVwVUvT43xP2bmePLOYZCbAwDQuf12QcXymkhsPcO6yQgIq/Jdr7FhgaE4G7PhL0\nLebujMo/WAe3MLlrWiUUtkI9pV2CimBt/igmp5tiVR/QeB768C6RfrNSUB/1g8Dg\n2SuxvMJjRPiqvUrqEYHO6P5gkfhBZxHPjmAb+HQGqfCz4vG5vw+XvpH1oif3jB4A\nEv/w/gtyrB5sEdxW3bp9e20mESW5DxQPeHsF+b6JgaqzLbhMUa4=\n=JBgd\n-----END PGP SIGNATURE-----", + "payload": "tree c03f88d24809204587b25a676afc09f98ef23c38\nparent 1a34269cb1fede931153172fdeaca034ccadcda2\nauthor eps1lon 1607965447 +0100\ncommitter eps1lon 1607985481 +0100\n\nAdd view for errors/warnings in inspected element\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/6cc7fdb8642f40c34d067f991dd01bf45149883e", + "html_url": "https://github.com/facebook/react/commit/6cc7fdb8642f40c34d067f991dd01bf45149883e", + "comments_url": "https://api.github.com/repos/facebook/react/commits/6cc7fdb8642f40c34d067f991dd01bf45149883e/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "1a34269cb1fede931153172fdeaca034ccadcda2", + "url": "https://api.github.com/repos/facebook/react/commits/1a34269cb1fede931153172fdeaca034ccadcda2", + "html_url": "https://github.com/facebook/react/commit/1a34269cb1fede931153172fdeaca034ccadcda2" + } + ] + }, + { + "sha": "59ddad1a8affb078724fdb58b296bf9258f3a183", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjU5ZGRhZDFhOGFmZmIwNzg3MjRmZGI1OGIyOTZiZjkyNThmM2ExODM=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T17:51:01Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:02Z" + }, + "message": "Serialize args", + "tree": { + "sha": "22fa26394637f3952c0dae32deaf70fccfab7f83", + "url": "https://api.github.com/repos/facebook/react/git/trees/22fa26394637f3952c0dae32deaf70fccfab7f83" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/59ddad1a8affb078724fdb58b296bf9258f3a183", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UoACgkQWCcTbp05\ndTKKgg//cXGgGOH+MG7vM1+c0dYHViLuQU3aByyFv4L+sVpODFPRZFEo8VifqN9f\nOttCyW6Kj2zQ6pE/sp30wAEWSeT8ZkaN2FYoYyclP2BnIUsyzXnoznnjHv78yTvr\n5lVQTy0Xv7Eev55WEAKxqhneK0OzWv7dGCwNZV+wNX+oTQ3t/Ozmy0+rx50JBVeR\npYNKummF6fMTME8Ss/QfERIfpVkJ/4j9ADZwR7CKzHWgkxvMdbD++cM4d6YI9rM+\nizGCo8vldYO7Faeb6C83D/v1AWCIlRMTEheSU/yRCh/XQx0Sjl0oCeAcJ8OK2b9T\nwEgCipYRTy8XTMccI0S4hmeuxDSPDGasVEbCk2UROEbDpST8iO7ov65oE1fMJLaU\nR/7yu3DbPkaD91kek/yoEJvI/+Ym0MVkWNvvxcY8MT2dT+iE0EIrHpeifx5sFWDC\nB9uj65rKuJ+Uws70pZFT1YP0CDH0uAO98PgsUw+WPOybwVG9vQjP/qoAKLi1oySR\nLTAcUVqwruU1GhS5MTHwbOwJ2G8nBICzdHT3zot+7KhjQ1YC8o0sn6OxXWmWF80K\nbOzAQE7tRepCp0wPP98txGCO7XmNUAmCSFYAiOACzr6QExHFJYqbK2STDOOfzEEU\n7jSNx/r+iuumplx8MEBlzgu6NlfmIYloreG0ENhHSK8/308PKcM=\n=oTZ5\n-----END PGP SIGNATURE-----", + "payload": "tree 22fa26394637f3952c0dae32deaf70fccfab7f83\nparent 6cc7fdb8642f40c34d067f991dd01bf45149883e\nauthor eps1lon 1607968261 +0100\ncommitter eps1lon 1607985482 +0100\n\nSerialize args\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/59ddad1a8affb078724fdb58b296bf9258f3a183", + "html_url": "https://github.com/facebook/react/commit/59ddad1a8affb078724fdb58b296bf9258f3a183", + "comments_url": "https://api.github.com/repos/facebook/react/commits/59ddad1a8affb078724fdb58b296bf9258f3a183/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "6cc7fdb8642f40c34d067f991dd01bf45149883e", + "url": "https://api.github.com/repos/facebook/react/commits/6cc7fdb8642f40c34d067f991dd01bf45149883e", + "html_url": "https://github.com/facebook/react/commit/6cc7fdb8642f40c34d067f991dd01bf45149883e" + } + ] + }, + { + "sha": "9372221a7a6f83decce2df7f08ade4b45957386b", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjkzNzIyMjFhN2E2ZjgzZGVjY2UyZGY3ZjA4YWRlNGI0NTk1NzM4NmI=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T17:53:18Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:02Z" + }, + "message": "Ignore component stacks in inline errors view", + "tree": { + "sha": "ce254bc5b1de16aa7ded980081abc2c599bd10e6", + "url": "https://api.github.com/repos/facebook/react/git/trees/ce254bc5b1de16aa7ded980081abc2c599bd10e6" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/9372221a7a6f83decce2df7f08ade4b45957386b", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UoACgkQWCcTbp05\ndTJUbQ//UN7uc5SVyFIqXLuLdaIH1aGcXul+G/EMYDaQ4fET+MYWrc71yHvfuRRU\nIqwEVOXJkTkjxh0VmmS/+sihkEQkoNHn/466g5ChJ3BRQ7lh4l0JDZD5TtJOE/nX\n65/7S56a3g/okBMtDHi2Io926WGvvARrbiT3YIkq7PXRpp67Ut9wtZp5W2xqmiDC\njg+zI4M9TDx0yxr/iiA4sH6+xa8mWze8Fr8H15/OHJbZ7lDV+d134PXXWjGf7Tbh\nxxiKMTDzuZMC00wDyElUl2rRluqGTIeJJz2ydPdg5YsO/8spxgy7/j1+ZGi7klZC\ncqU6q71HsGeK1ZFlnFGyB1ubSPgC20WLwWToHWxOvwI6BXXAq4aJWTjRVVHVya7B\n2YmC+LK7SErEuSvCBC+0v6OhCNeSY0d4hr0xXmKtzf6CUAIL1I5ffWC+ySbmv8/r\nSW/e5CRcN9lS0Av56lYXqQTKg3Dg6iGQ7BVPA9Ql2WjiH1H12YkhfjYh0Hmqgq1Y\n4qNoJSpfKKTbdyjgLfFKbJSV+MrhoH2x60gyjnrQITGw2kxXKR5rwjNBBr6eqynv\n9D2zaAjZNlIBXRkmJVaCcikcaSxRWVULMr9hwXT6fgCzVzi+3biHl7bk/Fznm42J\nnj240zft+gv/M5ncYFgooJ77lsy1VV/F7D9IDQisuCwVGsJxa04=\n=sxB5\n-----END PGP SIGNATURE-----", + "payload": "tree ce254bc5b1de16aa7ded980081abc2c599bd10e6\nparent 59ddad1a8affb078724fdb58b296bf9258f3a183\nauthor eps1lon 1607968398 +0100\ncommitter eps1lon 1607985482 +0100\n\nIgnore component stacks in inline errors view\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/9372221a7a6f83decce2df7f08ade4b45957386b", + "html_url": "https://github.com/facebook/react/commit/9372221a7a6f83decce2df7f08ade4b45957386b", + "comments_url": "https://api.github.com/repos/facebook/react/commits/9372221a7a6f83decce2df7f08ade4b45957386b/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "59ddad1a8affb078724fdb58b296bf9258f3a183", + "url": "https://api.github.com/repos/facebook/react/commits/59ddad1a8affb078724fdb58b296bf9258f3a183", + "html_url": "https://github.com/facebook/react/commit/59ddad1a8affb078724fdb58b296bf9258f3a183" + } + ] + }, + { + "sha": "34500ea568a52daddb1ec8f5858afb74c326e5d8", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjM0NTAwZWE1NjhhNTJkYWRkYjFlYzhmNTg1OGFmYjc0YzMyNmU1ZDg=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T18:37:54Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:03Z" + }, + "message": "Add icons for warnings and errors", + "tree": { + "sha": "0d5fcf8a526cba6e1129698edac774a92a7bb89a", + "url": "https://api.github.com/repos/facebook/react/git/trees/0d5fcf8a526cba6e1129698edac774a92a7bb89a" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/34500ea568a52daddb1ec8f5858afb74c326e5d8", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UsACgkQWCcTbp05\ndTJqjA/8CefBC+nGr5sppylJYb9hyH+kwr+RSCTALyQ8hhc8gJet+KkMRwG/cSo2\nPm+1TtkoUPcjDgktsyVWMpFsJxa/wtNniyf2C1iMQYuiAXw9B7GqUh4RarF7Aa4u\ni0WQ7FwWZ+YPn5Mxa7compMrJ4i7AmNnjbBhwS8gzxvGXLLZL32ZeanYYlNaR2DC\nECuXaj3yBKNgwGWhHgLdXPWAxnn7wXILgLLnHTBErqV29TsjaCxCTmtNsDXMKS0A\nT+e8pnSUrp0Ow02n39/XQObdgRz/KJlVYFbEJTmg37HXcR+RovRprCP/HY9+hoP8\nFiiQ8YU1ShTymkUqXrkSR0ylq5pYlWZsNLLccn+5aKxJN5d7xXmzEL9rPOmlvzb9\nwPetizjXT9qanrE8qTrmGSZCvMk/PJupHyIiFJ/AgPRdpLLiqaoA1VzJLBGD5GHR\ns/YEYC3KGM414G5U+Z8y5HZBth3BcXQTudkXamxJ9D4gDchilFwHrGRS0HVVYZLP\nEOFLBaTxaO5cJmcx/czHPo7D84N7PVUSEkzmQ+qqc3c4NWlwQqHCENeQxV+COy1K\n/NbsJaF6PjDv4MP3aiaWkbTN2eqTO5ojCM5709XfGmPcK+kfnTCAQi4kHcCoXmNb\nH1zfRNXoN19XLU5s81nVhU/qp9adR/IgcR4sXfTM0puS56d24NE=\n=FlSX\n-----END PGP SIGNATURE-----", + "payload": "tree 0d5fcf8a526cba6e1129698edac774a92a7bb89a\nparent 9372221a7a6f83decce2df7f08ade4b45957386b\nauthor eps1lon 1607971074 +0100\ncommitter eps1lon 1607985483 +0100\n\nAdd icons for warnings and errors\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/34500ea568a52daddb1ec8f5858afb74c326e5d8", + "html_url": "https://github.com/facebook/react/commit/34500ea568a52daddb1ec8f5858afb74c326e5d8", + "comments_url": "https://api.github.com/repos/facebook/react/commits/34500ea568a52daddb1ec8f5858afb74c326e5d8/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "9372221a7a6f83decce2df7f08ade4b45957386b", + "url": "https://api.github.com/repos/facebook/react/commits/9372221a7a6f83decce2df7f08ade4b45957386b", + "html_url": "https://github.com/facebook/react/commit/9372221a7a6f83decce2df7f08ade4b45957386b" + } + ] + }, + { + "sha": "962f08cf82500d925596d7d566cc697ba07c7394", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjk2MmYwOGNmODI1MDBkOTI1NTk2ZDdkNTY2Y2M2OTdiYTA3YzczOTQ=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T18:42:06Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:03Z" + }, + "message": "Cleanup unused console logs", + "tree": { + "sha": "9e6e0cc39547c223b30fe425f8c3ac1a68ee8737", + "url": "https://api.github.com/repos/facebook/react/git/trees/9e6e0cc39547c223b30fe425f8c3ac1a68ee8737" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/962f08cf82500d925596d7d566cc697ba07c7394", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UsACgkQWCcTbp05\ndTIsMg/7BE6QChDLAzHfFTTTYqSPtjvHKp8jkMpV+D8RshNMlaoSoMCOjtTQNm0z\n+YHTIYG/5YR6vXm3BsL2ZrZZR/rGeYw2tq62VVZOMoobGDmYNWynMQ/hhqU+NtOn\nsgFd5ADYdi7cxZQNRSfrctvx/J168lbOji7HwjHJdmj2yWBeOP0YYMqd4veQUsUY\nsbvtXNGtNbBCApHYzCmBjrHuyWcHz2t/PznJQSFwK3QdtRF4uQ1LNTowp8ep+fVx\nQGkluJcLGYm7pX5o/AtzdGovwmkpx9eSgdmlRAWqnPAMbSmzGD0uZtaWFSkRZvtz\n3lPZX/Fn5otkiyr+zn+LWRDCbVmmsUwMKmPBPtqZFf5HGGxU/33cLilu5bWwT5Pl\nENpsUQ1oLHy2DC/r/tYhPiWhLolzWo5I8qOATj19ysoGSopQUo0WiX01XXykq1tK\n0hL9WXOEtW7q36/nRYtkNIrPraEoGyYdBryd+20G3Jy23JDR8aLMb73eyXaC6uZ/\nd37NSJSciPziMU0uuasc1QvPCpnLkJfMkLijfRJMlmZtY46E4811unlH2lr3LcH1\nfhKUiu7pvk7veA/HEgPgCaxsxSl1rU7jTiojmUTbKw0CN5zbS0EroQNu1987BzJ0\nn8q0ZRfwzAgVRfMByfXqbl53EfmppPkOl8LoGN0ILNnkJRf1pk8=\n=Hyzu\n-----END PGP SIGNATURE-----", + "payload": "tree 9e6e0cc39547c223b30fe425f8c3ac1a68ee8737\nparent 34500ea568a52daddb1ec8f5858afb74c326e5d8\nauthor eps1lon 1607971326 +0100\ncommitter eps1lon 1607985483 +0100\n\nCleanup unused console logs\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/962f08cf82500d925596d7d566cc697ba07c7394", + "html_url": "https://github.com/facebook/react/commit/962f08cf82500d925596d7d566cc697ba07c7394", + "comments_url": "https://api.github.com/repos/facebook/react/commits/962f08cf82500d925596d7d566cc697ba07c7394/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "34500ea568a52daddb1ec8f5858afb74c326e5d8", + "url": "https://api.github.com/repos/facebook/react/commits/34500ea568a52daddb1ec8f5858afb74c326e5d8", + "html_url": "https://github.com/facebook/react/commit/34500ea568a52daddb1ec8f5858afb74c326e5d8" + } + ] + }, + { + "sha": "3104b1e7463aec62683125e9a5e63538fb533ad2", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjMxMDRiMWU3NDYzYWVjNjI2ODMxMjVlOWE1ZTYzNTM4ZmI1MzNhZDI=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T18:48:54Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:03Z" + }, + "message": "Fix flow issues", + "tree": { + "sha": "076dc54776a0f91a7cb4254de6e2f2e96eb38093", + "url": "https://api.github.com/repos/facebook/react/git/trees/076dc54776a0f91a7cb4254de6e2f2e96eb38093" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/3104b1e7463aec62683125e9a5e63538fb533ad2", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UsACgkQWCcTbp05\ndTKlbxAApJluvNix710CinqHwcit86D8YFzFZmELKV9CR71J1ZTrMcbFS5vh3Aqn\n11XbbeBWuifqQyvO+1HH/IgUpcTFW5POiWuz5nDLXPZCPE4h+vdDhVcmPK6ZIM5k\nSp54M9A/ZlOlQDaQBDgZ7Ce323d/GfaJdAmIR1gHZPj071XJIlcMooV5ABxBL/2t\nfsFJWORMRN+EGEMLl+R0uOhFEfiGeW89wx0D2OqA0n9LIh7Cfa8y+fIhMn6CHo0v\n71jKjEF5NBg/BwFpS8A3bW9s594IDtbEITFDgPBHXUl3rDaIGXhVgs7cN42sWZGJ\nNkQwpQh75rP6nUpBo9LSWp5NpQT0gAcO5Rk47mPgm6MYhqadEhCSq3OVNWTxw1gD\nMOgBD+p5xErkxaXRtimvElSME7sdHu5DkvQoArxgXjkpInE2Kr+yUmP4BFoRL7QH\n1md9Y1966PMisQTCh8VhemWjh2U3FDT2yyxY8wanXq8nOHP48Q/qV5UFJosUOT6+\nQZOBRe0nJl//bAEeN7yptrPoq+KUAgkKTEnUDZEtFbr0UbwqvSeaHXT03OOz0yUl\nVEr71FDpI4DtNPO0a68Y7WnKRVB3KTl9wljYKCfbhA2D67kUjc1gzRaH0bh3N02V\n0EXL1oyd/cAlqFHF2/cJ5t6Y/a23HrrjvOI4BzC767z5Z2CCcZY=\n=MdlC\n-----END PGP SIGNATURE-----", + "payload": "tree 076dc54776a0f91a7cb4254de6e2f2e96eb38093\nparent 962f08cf82500d925596d7d566cc697ba07c7394\nauthor eps1lon 1607971734 +0100\ncommitter eps1lon 1607985483 +0100\n\nFix flow issues\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/3104b1e7463aec62683125e9a5e63538fb533ad2", + "html_url": "https://github.com/facebook/react/commit/3104b1e7463aec62683125e9a5e63538fb533ad2", + "comments_url": "https://api.github.com/repos/facebook/react/commits/3104b1e7463aec62683125e9a5e63538fb533ad2/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "962f08cf82500d925596d7d566cc697ba07c7394", + "url": "https://api.github.com/repos/facebook/react/commits/962f08cf82500d925596d7d566cc697ba07c7394", + "html_url": "https://github.com/facebook/react/commit/962f08cf82500d925596d7d566cc697ba07c7394" + } + ] + }, + { + "sha": "cf3f212b2a387797c59b82fb08da4a547ad641b8", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmNmM2YyMTJiMmEzODc3OTdjNTliODJmYjA4ZGE0YTU0N2FkNjQxYjg=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T20:19:38Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:04Z" + }, + "message": "Implement clear(all,byComponent,byErrorOrWarning)", + "tree": { + "sha": "3864a094edecc0304d08016e15a23f72c625757c", + "url": "https://api.github.com/repos/facebook/react/git/trees/3864a094edecc0304d08016e15a23f72c625757c" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/cf3f212b2a387797c59b82fb08da4a547ad641b8", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UwACgkQWCcTbp05\ndTLjkA/7BBtp2DX/lCGFqRyblbrwanQtd44flxrzoLs4cIjdINyj/UA3vNBecgk+\nkrQKUJd5P00j8vDM6Al7KQnKARoc878rZF74fd8+cINXsiM9cx9BbaRbPlNB13wf\nJ9nQgZ/fyGKHyWBqXwDqlAOxvYSwvw8Dn5hX419dCkoS2shhw7XYe+BObXk4lKar\nWb84e8UpMuS8N+07PrsJlPXarHq5gxE1Xc5EddxBPH8npmOKxgn/KDMZZQp9ixtV\nJFVahGYceVjC/85PQmQzi1TZx8q2hrU6ezq3I0qK8bKlDhSDs7r6B0rlWH6q67Eh\nX7Al2q9sRTIaM8nla2ATEsfaXo/L4FLYLjOxC9ISSBaFQtdKZ5MozCU2hqiffb0H\nywRwrqyKSUh/NrNPZ+VYg15MYzlBm+pj1K/5G3eIoCei4udeQDNEaEXtVWUbTpmi\n2yKIOJ/dkSHWDTB1n/MLZXMeks7mJ0nYsFHSiE8YxdJNI27Ypk+EXg+79eKi+vdh\nSnN5ItiFZjOgZ6D0DETS3XrWMfWq3k+nTdv2obTqed1YO9inNc29o2Yi+Gs/COnp\n0RejYWl2YuLXxp1dVOP37U/g0MSoI8PiMPKyLHqX6IH2Jdfi+ELHZpB2kPHdRENB\nAt05IcuZlDPT2Ge1Mc8vvQ8z3GNAqwixsIkkdrewXdmZi5eyv0Q=\n=v1Ni\n-----END PGP SIGNATURE-----", + "payload": "tree 3864a094edecc0304d08016e15a23f72c625757c\nparent 3104b1e7463aec62683125e9a5e63538fb533ad2\nauthor eps1lon 1607977178 +0100\ncommitter eps1lon 1607985484 +0100\n\nImplement clear(all,byComponent,byErrorOrWarning)\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/cf3f212b2a387797c59b82fb08da4a547ad641b8", + "html_url": "https://github.com/facebook/react/commit/cf3f212b2a387797c59b82fb08da4a547ad641b8", + "comments_url": "https://api.github.com/repos/facebook/react/commits/cf3f212b2a387797c59b82fb08da4a547ad641b8/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "3104b1e7463aec62683125e9a5e63538fb533ad2", + "url": "https://api.github.com/repos/facebook/react/commits/3104b1e7463aec62683125e9a5e63538fb533ad2", + "html_url": "https://github.com/facebook/react/commit/3104b1e7463aec62683125e9a5e63538fb533ad2" + } + ] + }, + { + "sha": "5b3fb893b3609953bd1bebfc401a158bd82d7abd", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjViM2ZiODkzYjM2MDk5NTNiZDFiZWJmYzQwMWExNThiZDgyZDdhYmQ=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T20:29:01Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:04Z" + }, + "message": "Expand showcase with error and warn/error mix", + "tree": { + "sha": "da464d2d9940b7076b157fe6f10e9257c32b43de", + "url": "https://api.github.com/repos/facebook/react/git/trees/da464d2d9940b7076b157fe6f10e9257c32b43de" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/5b3fb893b3609953bd1bebfc401a158bd82d7abd", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UwACgkQWCcTbp05\ndTJl3RAAlNVn3qmPYP/gxwMFM825kV0os1FnzmPo2/VUoWLfNlZ1tI5jCmUUosj1\nRP1Kclhix6q39jpWcsdp8CLBw/QrehdSKHEmD7+2OugdOaRGLvPE/z9ou6zCrMxR\nUQfcfG/LDQzFrP8KTe7Nj0/4mezFDTP9X+1Rhs9srNXH3UHo06IZsTcSjLjvMRlO\ndRRIp+PGBApWiNzBZyQDHZ5UiEh+4OlpFT0QayrX0sm4pquwYSNMHN6IQX16h2CO\n7UaZs/2rie0a+rRiKt9yu95A34GBrec0lY6Rm8xs6eaj1AfI/oPLOwWY1veGMiB7\nPcub1vYWhDEyilaG0MMm18QwPUQSW+Vhmaug3mbCEzveu+0Gy8a+axijDEfX9hWG\nSl+G0LsvVsjg07k4+ayXQiox3oJvtalGwF7qzpKBglVzwYqO9c4InsXkh30xRd9D\nBbPnMq7GB5Y280fVrbxWIqVgEzEAFxvyhLHDD+dxM8TASJSiMTPcfayTQrfIV8NB\nj8b/GKmy8M/cDpKc6Hn8hDtCVSUIqZfwCAY/rkVtA61/tyvo2xZc8WwzlhvgvSWV\n9Kg9hUwpTTnpOHZ7qmj5QSQE8pLewfpXetZUt5Z7/TTYdbaV/BhYHJ5QPOoW/AnF\nFA3gd6ze0c6ShgG/o13zGWQb+bVfzxRfMb3GDmL4qB0xaQdk5ng=\n=W+GF\n-----END PGP SIGNATURE-----", + "payload": "tree da464d2d9940b7076b157fe6f10e9257c32b43de\nparent cf3f212b2a387797c59b82fb08da4a547ad641b8\nauthor eps1lon 1607977741 +0100\ncommitter eps1lon 1607985484 +0100\n\nExpand showcase with error and warn/error mix\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/5b3fb893b3609953bd1bebfc401a158bd82d7abd", + "html_url": "https://github.com/facebook/react/commit/5b3fb893b3609953bd1bebfc401a158bd82d7abd", + "comments_url": "https://api.github.com/repos/facebook/react/commits/5b3fb893b3609953bd1bebfc401a158bd82d7abd/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "cf3f212b2a387797c59b82fb08da4a547ad641b8", + "url": "https://api.github.com/repos/facebook/react/commits/cf3f212b2a387797c59b82fb08da4a547ad641b8", + "html_url": "https://github.com/facebook/react/commit/cf3f212b2a387797c59b82fb08da4a547ad641b8" + } + ] + }, + { + "sha": "d2c8e339ed0c75b0b197905a7d5bd49eb88e6c49", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmQyYzhlMzM5ZWQwYzc1YjBiMTk3OTA1YTdkNWJkNDllYjg4ZTZjNDk=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T20:46:27Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:04Z" + }, + "message": "Fix missing color error background message", + "tree": { + "sha": "6ba913b9dd1691373a90ab8b56a01c58d5eb46d8", + "url": "https://api.github.com/repos/facebook/react/git/trees/6ba913b9dd1691373a90ab8b56a01c58d5eb46d8" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/d2c8e339ed0c75b0b197905a7d5bd49eb88e6c49", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6UwACgkQWCcTbp05\ndTILJA//S8eYWMq4zsU0SySITqps6UZUy8RDMzJ5b5sDsHfrHRcJdMy1XXiK/kws\nBZO24yA5/iAVqA9eOADjMYKaXo03ax3fMb6apGQHcvXuUE+M7nuGmQKgWuDL7dTf\nslnvMvOMPSKhkMwBrDvxITCo2ouFLSwD1dzWoDfWA+izhZJY6wLy0rn4Vjqn1PME\noN0DXLy4GVueKCqyvL+x8lf2ozYT52ihu5y7DlxEhur9HFIMrCtcNpsRygrgFEr2\nl19C4sJJRKprXUHP2TTQ2+H5tlaXIN2zUC+wI2P00nRzEJ2TZ1OVFnV9ZAM6T62h\nalMaGDWSNjhkcZ24UCSZzBFgNoMJ+6gPMceQVKNZ7QHJqc6Aue4s1CPiH82Scynq\nJz0TwC4LL/p+C/ZVqkUrEUV6PuZulFETk/AeP9lgTzVWChX+R2L7XeLQMqCLFgev\nICK46u1znh6pv/N92fEA0ZMtQA1hRiTS1PWG4ckKBRiR4Zrj7Win+kFX5t0hE5eN\nfxgJw0N46GXsMkS6sBTcaCSbQJ+cTkiB0mXW783oUB5dgDr9zb1KgmLCJ8UUOJ4/\n9o4iVpxFKprVRel3+RMME0o8MGfYtR4hkJA1rlqGn1bcGcorqE7PzL1BwxQ7Yd1o\nWUkQmeguy+cq2LvN9LQ3wgOMwvB3E/2DXu217YoO/YlXNqQcsck=\n=wqWW\n-----END PGP SIGNATURE-----", + "payload": "tree 6ba913b9dd1691373a90ab8b56a01c58d5eb46d8\nparent 5b3fb893b3609953bd1bebfc401a158bd82d7abd\nauthor eps1lon 1607978787 +0100\ncommitter eps1lon 1607985484 +0100\n\nFix missing color error background message\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/d2c8e339ed0c75b0b197905a7d5bd49eb88e6c49", + "html_url": "https://github.com/facebook/react/commit/d2c8e339ed0c75b0b197905a7d5bd49eb88e6c49", + "comments_url": "https://api.github.com/repos/facebook/react/commits/d2c8e339ed0c75b0b197905a7d5bd49eb88e6c49/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "5b3fb893b3609953bd1bebfc401a158bd82d7abd", + "url": "https://api.github.com/repos/facebook/react/commits/5b3fb893b3609953bd1bebfc401a158bd82d7abd", + "html_url": "https://github.com/facebook/react/commit/5b3fb893b3609953bd1bebfc401a158bd82d7abd" + } + ] + }, + { + "sha": "dc92fef4500a214ebb1ff8985686a0338414a93e", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmRjOTJmZWY0NTAwYTIxNGViYjFmZjg5ODU2ODZhMDMzODQxNGE5M2U=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T20:55:06Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:05Z" + }, + "message": "Highlight elements in tree\n\nBefore we had to vertically and horizontally scan.\nBy coloring the rows, vertically is sufficient.\nThough I'm having a hard time in light mode. Dark mode is better.", + "tree": { + "sha": "58c79609ae46c806549ce52381a16d62daef7b94", + "url": "https://api.github.com/repos/facebook/react/git/trees/58c79609ae46c806549ce52381a16d62daef7b94" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/dc92fef4500a214ebb1ff8985686a0338414a93e", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6U0ACgkQWCcTbp05\ndTKbFA//Vqo7oZllW97uPrjWh6TZK9koipPsQ6xdiC5M0UeH1mCFv5jafoGPb+RY\nyWz897KcGysQV67F/L+sfKJrYkyWp6oxFkr8vCy8RuIYlPvwltJReLyAdGohr0UP\nzx0IMfvXDE2se2F4mwVPN8BgvEIIYWhPbm6cX4Vbua7ELXfEC+2AxU9PaIv2VqqL\nJcaGgZBbQtcQbcqz6QRKurrW7qFqAUX/xd0gNOn35wT95cvp1sP1sfsSeAdXMsnZ\n+nzpyZmTWkPyebVmHQHPjL3zFhE2apC/EajI+53qOS6NBVSRzaVLv8UCPtfEAEID\nI3X2nyPWrr05YarRGvWoW3YjdvHMRWrb3RcR6ZEKq8/pFYML6xdiPKQyHQuut8yj\nrzROk+QZDW8nAyGUauR6cVL0r8T1UbYHUfUpxlHeQV2d++j6pPjAnJpKo2FuTw1h\nUcPsPsn01DSXZ0trrrohBPeGBuW2JNN8AjyItGfSBbkIWHnKtn1nM5SgTaYGbuAi\nOjhBaBrezGICxuCH9L8B/+iYYF7pJKPp4za3NbOf0xqVdtyuzWNndn79MHv91kj5\nV5PwpiSYEgftEVWrqZ0ViyTyXA48khliKrpfMX0W4WHoNK31PaY/PTxUSU83mCQk\nsndR+mbJNCfcNCfEfPKPWv0tC+Mt2uk42AqWoxgj/RyIkNPtmqs=\n=zf7f\n-----END PGP SIGNATURE-----", + "payload": "tree 58c79609ae46c806549ce52381a16d62daef7b94\nparent d2c8e339ed0c75b0b197905a7d5bd49eb88e6c49\nauthor eps1lon 1607979306 +0100\ncommitter eps1lon 1607985485 +0100\n\nHighlight elements in tree\n\nBefore we had to vertically and horizontally scan.\nBy coloring the rows, vertically is sufficient.\nThough I'm having a hard time in light mode. Dark mode is better.\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/dc92fef4500a214ebb1ff8985686a0338414a93e", + "html_url": "https://github.com/facebook/react/commit/dc92fef4500a214ebb1ff8985686a0338414a93e", + "comments_url": "https://api.github.com/repos/facebook/react/commits/dc92fef4500a214ebb1ff8985686a0338414a93e/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "d2c8e339ed0c75b0b197905a7d5bd49eb88e6c49", + "url": "https://api.github.com/repos/facebook/react/commits/d2c8e339ed0c75b0b197905a7d5bd49eb88e6c49", + "html_url": "https://github.com/facebook/react/commit/d2c8e339ed0c75b0b197905a7d5bd49eb88e6c49" + } + ] + }, + { + "sha": "153358378a13d387622664908e6f4999d3dad55e", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjE1MzM1ODM3OGExM2QzODc2MjI2NjQ5MDhlNmY0OTk5ZDNkYWQ1NWU=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T21:02:15Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:05Z" + }, + "message": "Better spacing for error/warning badges", + "tree": { + "sha": "09433ef98d0b16beaaf96858f70c8726a85e896f", + "url": "https://api.github.com/repos/facebook/react/git/trees/09433ef98d0b16beaaf96858f70c8726a85e896f" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/153358378a13d387622664908e6f4999d3dad55e", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6U0ACgkQWCcTbp05\ndTLIKxAApx7VI8mjQ51Mp1/JeEiwvTXpvYFJ4GNEtkjityfj6n6ebtEAUm//4iUV\nz4N1UvTw4EpX+0IDHa7vebzL7FR7ui0Nv+OrGob/kTX2C0jYji04gKwq7cItlC9R\nufuhqKKiR/NoguUSDNJcf/MjKR6/hGFzQT+tvHpQX6B0gQmdQKnVJ85Njx1tH8Li\n+EVkUXsBjlHnPX5D93XerYKWBNNm73GXYg/8bmLe/Tx0pDYW/IH9n8Ymkl0C6+NR\nPCAlGUzpaDyw768weq5jWwTQ7qqvdAYYFhz5/0xFVlVnfZD4ROK4ITZgsHGzMe6M\nkkjbEikjBkmrcXQQo/RIHVykqdVojzH93vPrmGYZvx8xYL5X87sSTzuVHsTwVMe5\nlwsuMWhWC++mBzU9+rewTe1Evsx2mBJGXanCNYfAcmKnIqgkCDRn1ayC8FOsYCq0\nrwPqSDse/FwQkEURmsY3kwlWZmqN/J0otLVFYBOYH6l3c07DtNJCaKj+Bd/xQnjf\na5U6SIa6LZJbCmD1linPsvNfmjsDCKUSLHPRbM8zUar7qcjWlov+kNj2294976ko\nxtmplLia2bVa/8v/zd0zkOhsM2NFaAXDdpKbSfsJyjMyHfCUUIIGer05noA63KTX\nrWSv8oJm2bWLBaJeyLJK6ru6qBt3WvHflmedMdvBKo+ZnkdYNF4=\n=pAoN\n-----END PGP SIGNATURE-----", + "payload": "tree 09433ef98d0b16beaaf96858f70c8726a85e896f\nparent dc92fef4500a214ebb1ff8985686a0338414a93e\nauthor eps1lon 1607979735 +0100\ncommitter eps1lon 1607985485 +0100\n\nBetter spacing for error/warning badges\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/153358378a13d387622664908e6f4999d3dad55e", + "html_url": "https://github.com/facebook/react/commit/153358378a13d387622664908e6f4999d3dad55e", + "comments_url": "https://api.github.com/repos/facebook/react/commits/153358378a13d387622664908e6f4999d3dad55e/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "dc92fef4500a214ebb1ff8985686a0338414a93e", + "url": "https://api.github.com/repos/facebook/react/commits/dc92fef4500a214ebb1ff8985686a0338414a93e", + "html_url": "https://github.com/facebook/react/commit/dc92fef4500a214ebb1ff8985686a0338414a93e" + } + ] + }, + { + "sha": "4b46d94ec9564da0cf0b1a0ed31eb17b92d9d928", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjRiNDZkOTRlYzk1NjRkYTBjZjBiMWEwZWQzMWViMTdiOTJkOWQ5Mjg=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:00:34Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:05Z" + }, + "message": "BROKEN Implement walking through elements with warning/errors", + "tree": { + "sha": "9b025d9189a20a8e5d961594db35eedd56ea5957", + "url": "https://api.github.com/repos/facebook/react/git/trees/9b025d9189a20a8e5d961594db35eedd56ea5957" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/4b46d94ec9564da0cf0b1a0ed31eb17b92d9d928", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6U0ACgkQWCcTbp05\ndTItug/+JpAKHZaauHeA96YxvpX7xj7X6SFaHbZwbEwhaB3NWK73uCvJdjXb6MuS\nGY6vQEmLMcUTiaGKLWsPZpCTX2sbZItk1Fdf8U6N7JbxngGLPeHqSEmoSqPspGem\n0ZEEBkCAvZY6QJkcZWu5KMXHyDJq/I8022BauD5htz1Clnsk++/XGurfm89rUR/J\nvG0GUiJBnX8Yxd0M/edQUQByo1z5wyDIzx7rW3aW9aqw6NODGz4FxoI1lkvQL9NG\niXRWQG7xn1UWQOxZuH08tE3/NOvk5XUSHf2w88fs8mW5OFXNPlA7CqjGjp80grLj\nVwDaHsN7PvHvKQd9arUITnJ8wr3egkxtQJy7NatkEK9KEGOpNd2/7J0PO+QBxBIr\nYDs52N9VY0HWxkwPWmDwYdEtI1mv/Ldi9vq5a9+W7Pg2eZ1VdAmEkhuJOf49tIgj\nPgH+jMkSiJhCuPnMk6/tKI/FoJ9GKgAut7LTVPvyelWCg4707ijcdaiYGxBfXlKW\ntEn6pdi8rsv3CtU8i95Pe6x03F0TEtVQfq4FnlygkQMbKyE/Ao2hIpMva3xGmaQm\nyLeNGSgMenObMa7rTQwt5I/J3pYTES6y8q6JHbcuv7bwyI9jw656EryPwghv0ECU\n+glDCs7TwlLWzQ00i33uc5oxiQIEXnZhLsiyLj8yr8+Pp4tkd10=\n=I6Vf\n-----END PGP SIGNATURE-----", + "payload": "tree 9b025d9189a20a8e5d961594db35eedd56ea5957\nparent 153358378a13d387622664908e6f4999d3dad55e\nauthor eps1lon 1607983234 +0100\ncommitter eps1lon 1607985485 +0100\n\nBROKEN Implement walking through elements with warning/errors\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/4b46d94ec9564da0cf0b1a0ed31eb17b92d9d928", + "html_url": "https://github.com/facebook/react/commit/4b46d94ec9564da0cf0b1a0ed31eb17b92d9d928", + "comments_url": "https://api.github.com/repos/facebook/react/commits/4b46d94ec9564da0cf0b1a0ed31eb17b92d9d928/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "153358378a13d387622664908e6f4999d3dad55e", + "url": "https://api.github.com/repos/facebook/react/commits/153358378a13d387622664908e6f4999d3dad55e", + "html_url": "https://github.com/facebook/react/commit/153358378a13d387622664908e6f4999d3dad55e" + } + ] + }, + { + "sha": "ae89ee8e16a94f5333a17ce950dcd4cf001033cc", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmFlODllZThlMTZhOTRmNTMzM2ExN2NlOTUwZGNkNGNmMDAxMDMzY2M=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:03:36Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:06Z" + }, + "message": "Remove nullish coalescing which is only used in the scheduling profiler", + "tree": { + "sha": "ca68f511c06b6f137e01f131e31dfc76ad366d9d", + "url": "https://api.github.com/repos/facebook/react/git/trees/ca68f511c06b6f137e01f131e31dfc76ad366d9d" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/ae89ee8e16a94f5333a17ce950dcd4cf001033cc", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6U4ACgkQWCcTbp05\ndTJ51A//Q5mdYqrLd1tLHlSpod5eVi2MW5bk1rkUvIjbOZNOCN8Afr5r4ieV/RNY\nzrJs4BfGgLiaziIYL9lie7xnnjQzIhpoOXQos+4GVx89v9wWVs2Htscse770E/1F\nWwBkyToHNFM51JKRG/FjEaRLCIzMDWpzsiSDabkw0yM3YESLHF11RZ7VNqKCnfzY\nLFWUS46FnPPKyaD1aoPjJIOE9W1D3rFGe57exIgrTh9HcPuGYxCxCxsxU6E4cWLI\n9OF4WFOYHQ9J66qpEjUXHuFR6Gk9LJ11SSObT7loxMuLoOcKBvL4KxTPtoZf/C3r\ndLvXkhkWd0sq/muazj6SmTRboO7l9oiGvU+D5XHwDGvaXi3Tid9Hjhl4QDLA+ftW\nLbPidihELlWyT9/JC8Piq7sxdjydGeBO7rSIGu42JqiRXnB6Fr8GapcM89JA07Mm\ndxbfcVrMo07A0PN1WKm1s6NTsQtZ3Se3kmGlB5ZAE5oMylJJvaEensPdlQq19ROt\np4iAxX+P7ZzJ0DiywR/KJQxj3+XLQsYlsqNHGsTHpZYJR5tcqmCAikjRYZk98tP1\n1iCt24eZMj4cHlNzQhyOJQnYgg29ezhyd9LHWHl65utDVSzx+nv227kWLJN0Rrk4\nghk8R0TCQJU5IHW1ybk5CWS480wAvFc3D1MCTQYNwOiM/GaVidw=\n=Fnie\n-----END PGP SIGNATURE-----", + "payload": "tree ca68f511c06b6f137e01f131e31dfc76ad366d9d\nparent 4b46d94ec9564da0cf0b1a0ed31eb17b92d9d928\nauthor eps1lon 1607983416 +0100\ncommitter eps1lon 1607985486 +0100\n\nRemove nullish coalescing which is only used in the scheduling profiler\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/ae89ee8e16a94f5333a17ce950dcd4cf001033cc", + "html_url": "https://github.com/facebook/react/commit/ae89ee8e16a94f5333a17ce950dcd4cf001033cc", + "comments_url": "https://api.github.com/repos/facebook/react/commits/ae89ee8e16a94f5333a17ce950dcd4cf001033cc/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "4b46d94ec9564da0cf0b1a0ed31eb17b92d9d928", + "url": "https://api.github.com/repos/facebook/react/commits/4b46d94ec9564da0cf0b1a0ed31eb17b92d9d928", + "html_url": "https://github.com/facebook/react/commit/4b46d94ec9564da0cf0b1a0ed31eb17b92d9d928" + } + ] + }, + { + "sha": "6e41fc1b8d93a412616afab74e5e5a6791ee7ec6", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjZlNDFmYzFiOGQ5M2E0MTI2MTZhZmFiNzRlNWU1YTY3OTFlZTdlYzY=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:09:24Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:06Z" + }, + "message": "Bail out if we have no errors/warnings", + "tree": { + "sha": "fa08c38ebd2d1fe856dc06ea1ae7a3d3e6e331a8", + "url": "https://api.github.com/repos/facebook/react/git/trees/fa08c38ebd2d1fe856dc06ea1ae7a3d3e6e331a8" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/6e41fc1b8d93a412616afab74e5e5a6791ee7ec6", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6U4ACgkQWCcTbp05\ndTKj3BAAqBWpeYJItj/mLnCQyd4X89DBdbvsbLzpBVzmVEpAmN4HHkdQ7rkfhY4/\n1xw2HsSGHXKVOlSQj4YtEstHSvhVTE2OMKk4L+5LiEae0BsQ2XQdTjE4TWAW///6\nrttAyoz6W8cUP8Gx/CUgE+FEdubjlV6VJcL3c0aA4nw4pNPug9Jma+6JqU8e+LFH\npWfXy4oe0C+BntlPVz2Nya+VvGWfSJZtMUGW8Uq6m2keIoTTSLqftcHXrvGVJpGb\nn0F6NTPBsHapebpS0IlAM3ybXj2prqre6SELqQNWLbUeEXD6c7uxS6213ortwFfg\nH2vUqOnu7xxmSUn+Q9Zl9i/gv9zVo+V7D+jAJeYdiXKzjorJS4CWbHkgDAmOOymI\nFfeWYSSOlU1gP6zelCFt1ZF3IOYiBQaSMHkzhYzVu6bdWUr3IPdsovFzyvO8GCj0\nHGaHrmfJvitkndAPtzkwxdvk9o1+Y8gfl3hz8THo7RWjT8QIaBwQFF46+xsSxu18\nUNbGyLldSii178BHSDNAlGavKyO7fR2N62u51fYfd41rUWJzmFRuhzVr+ZVP8pN+\nyQz9yR4VRk0JY13X3z0G8QpdyK/+kWH0bICkJD8+zhbgx0I3Mf5FG8UlIgxsPBmX\nqo+4a/ztLJAblEV8WIdUG1ZIJodKu/04w/Ls4znY3yxdocur2BY=\n=ZEW6\n-----END PGP SIGNATURE-----", + "payload": "tree fa08c38ebd2d1fe856dc06ea1ae7a3d3e6e331a8\nparent ae89ee8e16a94f5333a17ce950dcd4cf001033cc\nauthor eps1lon 1607983764 +0100\ncommitter eps1lon 1607985486 +0100\n\nBail out if we have no errors/warnings\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/6e41fc1b8d93a412616afab74e5e5a6791ee7ec6", + "html_url": "https://github.com/facebook/react/commit/6e41fc1b8d93a412616afab74e5e5a6791ee7ec6", + "comments_url": "https://api.github.com/repos/facebook/react/commits/6e41fc1b8d93a412616afab74e5e5a6791ee7ec6/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "ae89ee8e16a94f5333a17ce950dcd4cf001033cc", + "url": "https://api.github.com/repos/facebook/react/commits/ae89ee8e16a94f5333a17ce950dcd4cf001033cc", + "html_url": "https://github.com/facebook/react/commit/ae89ee8e16a94f5333a17ce950dcd4cf001033cc" + } + ] + }, + { + "sha": "8de25ff9481f5bd960d589841fef88a475b68daa", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjhkZTI1ZmY5NDgxZjViZDk2MGQ1ODk4NDFmZWY4OGE0NzViNjhkYWE=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:18:08Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:07Z" + }, + "message": "Hide inline errors toolbar if there are now errors at all", + "tree": { + "sha": "a67553f215c55ddbd6e2349f6006bbf294194e83", + "url": "https://api.github.com/repos/facebook/react/git/trees/a67553f215c55ddbd6e2349f6006bbf294194e83" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/8de25ff9481f5bd960d589841fef88a475b68daa", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6U8ACgkQWCcTbp05\ndTJ5hhAAh9du8gc+wYbu/VxxN6oWW9tiXxaNSoeM/x2nd+KZDXXS1nVGMdmNdHv0\nIGHagynw2XVlv8PnV9t967avIIy6AmQRtOo4tjuIod9YKcHzovxVgTqOUlualMmk\nUfrQKNeFioHoaUuOcfOt6pP7XtU5N3V98PJnWliSceOrziZFzqy9Zy/qeT5kOTA/\nIaAx145+Uda69u/wzg0MrvGIqpONGrNDDzwx3WT6ZpfRm7/SjCpNmJQi1tj4v7s9\n9sGWB/YNng/i0cQzodI7M3JxxElEhDoVie7ebLMsVoU+2erGuf0qS4kC20AtdndY\n7pRlOBFpsSS3JjA2Fft3GEwH1BNlzXm9dMG8goWnQ/aWmt9uIlY6QmhHuGV2QNwN\nmZMbacTgWeKR1da91lntVu+DW1IpFQi2KEzGkSpiKl5vV/OMYGAK++B9Irt76tYW\n//l+nThWGAvNKE46Kf0wMu7j0XLBXt1Y7BQV0J3SU9VbAfFAE9XN7NCxPs9pU9LN\nCLRc3SgEhbXPgwisZmP/z/Grld8NJWLLfOB+2LsPqyjq9KrtNwCpvchK2MXDDpc3\nXDztE7t6YZ2CjuL2qNNJGIS41fYy8KTzlEs44qruqBWATba0JU+5g2AE6XqzJZdq\nSWuP2boSXoKNyUbh2IzFnrRXz4utlye5K+jI3NN7I9o+4WUjuv4=\n=Jotg\n-----END PGP SIGNATURE-----", + "payload": "tree a67553f215c55ddbd6e2349f6006bbf294194e83\nparent 6e41fc1b8d93a412616afab74e5e5a6791ee7ec6\nauthor eps1lon 1607984288 +0100\ncommitter eps1lon 1607985487 +0100\n\nHide inline errors toolbar if there are now errors at all\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/8de25ff9481f5bd960d589841fef88a475b68daa", + "html_url": "https://github.com/facebook/react/commit/8de25ff9481f5bd960d589841fef88a475b68daa", + "comments_url": "https://api.github.com/repos/facebook/react/commits/8de25ff9481f5bd960d589841fef88a475b68daa/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "6e41fc1b8d93a412616afab74e5e5a6791ee7ec6", + "url": "https://api.github.com/repos/facebook/react/commits/6e41fc1b8d93a412616afab74e5e5a6791ee7ec6", + "html_url": "https://github.com/facebook/react/commit/6e41fc1b8d93a412616afab74e5e5a6791ee7ec6" + } + ] + }, + { + "sha": "3560c40a81d69918c6017a155ec13ef47b4a4009", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjM1NjBjNDBhODFkNjk5MThjNjAxN2ExNTVlYzEzZWY0N2I0YTQwMDk=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:20:02Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:07Z" + }, + "message": "Remove outdated todo", + "tree": { + "sha": "dd8fc9eaf1929b7afde1ad865769de0bf1274f02", + "url": "https://api.github.com/repos/facebook/react/git/trees/dd8fc9eaf1929b7afde1ad865769de0bf1274f02" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/3560c40a81d69918c6017a155ec13ef47b4a4009", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6U8ACgkQWCcTbp05\ndTIxJRAAmImF6QdGgSxmKjl6e6IXg2oZy8raGAyfd+pXD3k8I/XBTYB8dwNI+UUA\nnhB9YXD0rY7Pjz8I8kstYT0NVEUKUbFhQiG8XIVomg0sb5kkx8TwgleQTBrdRme8\nKV5AjGs8c0NoDFV6qjsK/d6TvkOrCVSr2YIg9gH55qByy+wfsDbLH/ZtoeyQaeYC\nvPUGHbHC3UBeSaYk7BY3RnoEe+j65Gbqwf4q4BYgX/PyrDy8RMo0743jB7FhURI+\nWlD33UN7BUAjBprOgcmEau9l34rhhTmKREr5Hedtw4rfxNCMLFwrvpSkwTnGXZJp\nV8GizbC+3ahon8YmGHBFj1Z4RlhrIwqN/96rFqq38Rxu5TiPnxtfE3bOrFCGdqgz\nhA8HQfobR1serxHvmK3mQ28GeFlL2Ymva7IgsEw5ELj6YNIx9sx75hETnms38X7F\nd36W2T+XJl70wkch0gnUPFYAk5O6H352vNExhevvSD9X7ZN6qlXeCmmO26rc85ZF\n56gDjtBe893e4TBovcEItyaoRHRlaT/fqq/3K8pmCTH5jpi3JDFYNxnffgIUMFA5\nhwl1fsb08HmS8wBi0koYZPmNjGADln/YRznMX8proNDTq+RlhBjmh+I3tfMbnDIr\nhOVc51lcYpy7bYNL82RvAzof32lxGhFSsXtM4tNCo1uFN2iaokc=\n=cRE7\n-----END PGP SIGNATURE-----", + "payload": "tree dd8fc9eaf1929b7afde1ad865769de0bf1274f02\nparent 8de25ff9481f5bd960d589841fef88a475b68daa\nauthor eps1lon 1607984402 +0100\ncommitter eps1lon 1607985487 +0100\n\nRemove outdated todo\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/3560c40a81d69918c6017a155ec13ef47b4a4009", + "html_url": "https://github.com/facebook/react/commit/3560c40a81d69918c6017a155ec13ef47b4a4009", + "comments_url": "https://api.github.com/repos/facebook/react/commits/3560c40a81d69918c6017a155ec13ef47b4a4009/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "8de25ff9481f5bd960d589841fef88a475b68daa", + "url": "https://api.github.com/repos/facebook/react/commits/8de25ff9481f5bd960d589841fef88a475b68daa", + "html_url": "https://github.com/facebook/react/commit/8de25ff9481f5bd960d589841fef88a475b68daa" + } + ] + }, + { + "sha": "45f756236f782b8891261661b40270416e2da48d", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjQ1Zjc1NjIzNmY3ODJiODg5MTI2MTY2MWI0MDI3MDQxNmUyZGE0OGQ=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:23:22Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:07Z" + }, + "message": "Add keys for error/warn messages", + "tree": { + "sha": "d2d4806c4d3aa1563cb6694346da036ed47e4340", + "url": "https://api.github.com/repos/facebook/react/git/trees/d2d4806c4d3aa1563cb6694346da036ed47e4340" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/45f756236f782b8891261661b40270416e2da48d", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6U8ACgkQWCcTbp05\ndTIsFw//YwSpF1agJPGUfcU84geZRb0qwiBp0NhNZC9bxg+KGIYpNDJE4mOIS7JU\n3y8uyb9vNTzjfqSgPUu9VgMIi1tUS7NgT1Nvks2Tf7zNCwvem2pmd/bzzFSp2PE6\nebJ9VCgJD34luuc8u7HuSXxyZR8RF9dUcI7TOKD7aR9Jd+AXM2YkerfpT5e8SIFC\nbYv8F86JHe/n6v67TKSUESdXv29LhWVuIIs1K8MG0lvZzjwcroDwVeodyTCWaIBY\nToI6BAaqXNQz6WoahBKWN2N4YM2RI04nmQjjGII6f9ZiiRDzSUyHmhfo7V5wFu0W\ngdkrPvuLR1UqjF1gFpFJK0GSX93JMPVB7Ha8xuW6v971QQ7GDTBgPJSQ3JcFAYw+\njFM8cPk48I9DSogv2cQccNZGG4Q5HTN/MQ7fWTB49TydkyV71psYvDltjBuGgJHk\n3yb2cnMPcOM4GW/CpHU3GgCAxn4nJOzl25b3r5BuZeWYyGg719CEZ3sQ0vIPjGz2\nWZjhUADXqOXc9AyXydyCx2vwNPSqvHVQAx8l2qOXkrxSP6OnH1b1qHTDEYCdM7VT\nV10Lc8mVC6/IBEfBrujNdNS1hcUmYw8O1REZXqFxzc67TtVQaXXnaIGdkRHK0QEO\nUHHvl7nn9MYv9Y4uuCdSBVlXZv/JwYikwUuqI9pFEanIrnzKzEk=\n=P31U\n-----END PGP SIGNATURE-----", + "payload": "tree d2d4806c4d3aa1563cb6694346da036ed47e4340\nparent 3560c40a81d69918c6017a155ec13ef47b4a4009\nauthor eps1lon 1607984602 +0100\ncommitter eps1lon 1607985487 +0100\n\nAdd keys for error/warn messages\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/45f756236f782b8891261661b40270416e2da48d", + "html_url": "https://github.com/facebook/react/commit/45f756236f782b8891261661b40270416e2da48d", + "comments_url": "https://api.github.com/repos/facebook/react/commits/45f756236f782b8891261661b40270416e2da48d/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "3560c40a81d69918c6017a155ec13ef47b4a4009", + "url": "https://api.github.com/repos/facebook/react/commits/3560c40a81d69918c6017a155ec13ef47b4a4009", + "html_url": "https://github.com/facebook/react/commit/3560c40a81d69918c6017a155ec13ef47b4a4009" + } + ] + }, + { + "sha": "1dafc3b6fb076fe8376c4c21b5cba40b8b6b5b8d", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjFkYWZjM2I2ZmIwNzZmZTgzNzZjNGMyMWI1Y2JhNDBiOGI2YjViOGQ=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:35:07Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T22:38:08Z" + }, + "message": "Diff cleanup", + "tree": { + "sha": "81b3503d153a5bd1ec06d17c8d8da568339c0337", + "url": "https://api.github.com/repos/facebook/react/git/trees/81b3503d153a5bd1ec06d17c8d8da568339c0337" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/1dafc3b6fb076fe8376c4c21b5cba40b8b6b5b8d", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X6VAACgkQWCcTbp05\ndTIggA/9FW+7D4SyiWOb72z7WVDnP766KZc8hayVRjxFymHkGCBrGeFo/e+yqlGi\ntVTiz9Uvy+pUj5toyThvxg1JhDKZfk24pxUDKjwlm6LIjoTfwe8HjOpkwi9wTmpV\nmbfR+uZNWsDhCF8uhazIaugKCgVwxgFHy2WTvJYE0+RU32u98KoxkMpSO60unam/\nJVJqPgRfubsTNvLtb4824LncxXJfCXLm+o10lFeezcQxq1HcjBkvv/OuRsRPzX8T\nlJstYgd7SjqPAK3el8Iv2a8DFMom/zijQCvDSUHV+hMVI/8l4/s29MQOZxW8pZmR\nYgA27aCUlXX8SCmu0InmJZ0JNHqavO9zXJsavdX8dZmFQqhprdcbvNqYUFmx4U9N\nvV6nDA0bONRoo1uM69nlQBu38nIimrPyAZY7/ZPsWA/ZugIO7KQ9bQjvagtiNB/y\n4cSDsyEvJepcUmSjaYh22P7nM6LAIy4YdLiHF+HVpp9dCSkHajqD7KweoW39JcHu\n4UFERLIp0NXMr01esFS6kz5n0p706glaGi+TTx5QbCfY+yg7XyO5kxjHMHR+asg1\nWufWth+PE8JPofvMSN7vewI5s70w8lYmN5MYU7RiiBzO5cC79wRDILRNEXnV/lqK\nmDlzr6efExJmIsT1nJuXcWXR6PtTcBobkFC8kMlrq2pRvb7jchc=\n=qxgt\n-----END PGP SIGNATURE-----", + "payload": "tree 81b3503d153a5bd1ec06d17c8d8da568339c0337\nparent 45f756236f782b8891261661b40270416e2da48d\nauthor eps1lon 1607985307 +0100\ncommitter eps1lon 1607985488 +0100\n\nDiff cleanup\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/1dafc3b6fb076fe8376c4c21b5cba40b8b6b5b8d", + "html_url": "https://github.com/facebook/react/commit/1dafc3b6fb076fe8376c4c21b5cba40b8b6b5b8d", + "comments_url": "https://api.github.com/repos/facebook/react/commits/1dafc3b6fb076fe8376c4c21b5cba40b8b6b5b8d/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "45f756236f782b8891261661b40270416e2da48d", + "url": "https://api.github.com/repos/facebook/react/commits/45f756236f782b8891261661b40270416e2da48d", + "html_url": "https://github.com/facebook/react/commit/45f756236f782b8891261661b40270416e2da48d" + } + ] + }, + { + "sha": "e3e95fbf56947aeda4c416ac93eec5c8b0bc4f38", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmUzZTk1ZmJmNTY5NDdhZWRhNGM0MTZhYzkzZWVjNWM4YjBiYzRmMzg=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T23:03:44Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-14T23:03:44Z" + }, + "message": "Fix flow errors due to missing type narrowing capabilities", + "tree": { + "sha": "c5d6f2936a23a95b16b990bae912c6e371c4db62", + "url": "https://api.github.com/repos/facebook/react/git/trees/c5d6f2936a23a95b16b990bae912c6e371c4db62" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/e3e95fbf56947aeda4c416ac93eec5c8b0bc4f38", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/X71AACgkQWCcTbp05\ndTK7yxAAqa1ao5GaJPrTn+2jFlxpPWVdS/yU2TbyocumsMGNsxCMXAqMp8NgLD/2\ns6Qb22F+i4mdjppqU2DMyDc3+bG0hmPzW/9FB28UekjayTfp6CaO2COq86khrFMa\n+tqva15adFxz5UEx5rSREeQ1M8b0YSaJiCPxaBpEF4+RzN37RGqZev+emMGtEfku\nWE+lM8i1Sr/omRGG+SnbfkOCA3AlBbBqskhnkBy3JGEoESWMULpL8kF+MTjB1k8u\ndC0ft7CLyv2wh2kXM3qOa5s5qsltxBn6u4elDAmTEpcDOA1627czPKR2MvKP8RCv\nayVvEipcENBYAMGc82XDoY0GGN4AL1NxIblvYQ3pGVszYLEMKb1SWLqned17dpYk\np804d7Bx805amuhwWrmHCDyhN56xHUflW9omqEkaUwDT+DlbYll2p8F4Yl6TfJE/\ngbXpKvPytP+7Nl/ivexgLrKFajvWv7v6EYcciiVBjihROdprDJEzM1mttDVd4WuN\ncyTx7Cxz1UDFxiNnmLqqVpUt3hCtt9NWfKsytii2lZAT85U4QEAFaUF4Lj0vWJRu\nUwBJBhNVp3evjwKzNFCQgUdmnbxZFz0H9DFROtB88DSfs4FrfX40oAsp1vNYvW89\nJmTFIvQ9fpdE2f1H9ouWmLZ3OLCxR4GudrMmUxId3SxnkQRbNJ4=\n=BoOB\n-----END PGP SIGNATURE-----", + "payload": "tree c5d6f2936a23a95b16b990bae912c6e371c4db62\nparent 1dafc3b6fb076fe8376c4c21b5cba40b8b6b5b8d\nauthor eps1lon 1607987024 +0100\ncommitter eps1lon 1607987024 +0100\n\nFix flow errors due to missing type narrowing capabilities\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/e3e95fbf56947aeda4c416ac93eec5c8b0bc4f38", + "html_url": "https://github.com/facebook/react/commit/e3e95fbf56947aeda4c416ac93eec5c8b0bc4f38", + "comments_url": "https://api.github.com/repos/facebook/react/commits/e3e95fbf56947aeda4c416ac93eec5c8b0bc4f38/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "1dafc3b6fb076fe8376c4c21b5cba40b8b6b5b8d", + "url": "https://api.github.com/repos/facebook/react/commits/1dafc3b6fb076fe8376c4c21b5cba40b8b6b5b8d", + "html_url": "https://github.com/facebook/react/commit/1dafc3b6fb076fe8376c4c21b5cba40b8b6b5b8d" + } + ] + }, + { + "sha": "2aafbdf7718d1f25e1c69d738183db46aec09d12", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjJhYWZiZGY3NzE4ZDFmMjVlMWM2OWQ3MzgxODNkYjQ2YWVjMDlkMTI=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T14:19:08Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T14:19:08Z" + }, + "message": "Match UI of Search", + "tree": { + "sha": "2198afb099ba7da9a6753d7ade9f423be3117c6b", + "url": "https://api.github.com/repos/facebook/react/git/trees/2198afb099ba7da9a6753d7ade9f423be3117c6b" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/2aafbdf7718d1f25e1c69d738183db46aec09d12", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/YxdwACgkQWCcTbp05\ndTKf+Q/+Mk17VtK8Co6pzgkdc67h9M4mHESSi8OZXLDALEGCuUOmBL8lvpcV0y2O\nykyCE2usgTAbZnhoaulYpSHYXCfEYPi+QB1aSuBNfj3UBqQH//IOdvi/QE15SYLn\nq+UcUN0uVV66ZcWU3tp+piVipGrXjR4G4VYvQ1hdgnG5fgdTkHn9YEtW506J2XKU\nk2rFpICUghjvYaFTfwnTbXDtqAjolSDh0V/nL2jLGeltQcwZWSzJ2FA9fKzclIBd\n6gdzVnCb2h1ZXdpvutHe2HuuDbRyBnwM0n7ymY0LrdD41OISKzFP0qXS94jGkfbo\n2CvrPa4IIsErHMYdrNXlzaH3f7jIEIc7kj9tZ7JMoS5AmO1nOCcvB78Kr+3zZYDt\n62461+NHIpKwqaIGHjgNZKyThGh/iYkRJocCtDYyTVX91Vsr2fNTH3MzHNWl/CXt\nH9dRYSMtWjhrOirKp9IwPCRHhjCVCQN0lbmEfJa3Bm9ob0MISZXT/zbSIYkXom7G\nSruYUwN4LNMzQ2PXOnWG/gmxJlplwFcPhnye7G66tLp0NEFYsqX1VUF2v9MwxmPb\nUECcxnqlbHCEs9XE7cH90c6/lGb3G2jIzWsvkAOhsTc5yj2icFuIpRCh6dEWygu3\nMNlsDVnmjRW5Ray02adefebc1v7cS0BK0K6AE9a6z6ErQ0w1MAo=\n=FT9B\n-----END PGP SIGNATURE-----", + "payload": "tree 2198afb099ba7da9a6753d7ade9f423be3117c6b\nparent e3e95fbf56947aeda4c416ac93eec5c8b0bc4f38\nauthor eps1lon 1608041948 +0100\ncommitter eps1lon 1608041948 +0100\n\nMatch UI of Search\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/2aafbdf7718d1f25e1c69d738183db46aec09d12", + "html_url": "https://github.com/facebook/react/commit/2aafbdf7718d1f25e1c69d738183db46aec09d12", + "comments_url": "https://api.github.com/repos/facebook/react/commits/2aafbdf7718d1f25e1c69d738183db46aec09d12/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "e3e95fbf56947aeda4c416ac93eec5c8b0bc4f38", + "url": "https://api.github.com/repos/facebook/react/commits/e3e95fbf56947aeda4c416ac93eec5c8b0bc4f38", + "html_url": "https://github.com/facebook/react/commit/e3e95fbf56947aeda4c416ac93eec5c8b0bc4f38" + } + ] + }, + { + "sha": "64ad2e25324016e94167d6d1d29f07e362fe221b", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjY0YWQyZTI1MzI0MDE2ZTk0MTY3ZDZkMWQyOWYwN2UzNjJmZTIyMWI=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T15:44:29Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T15:44:29Z" + }, + "message": "Match UX of Search", + "tree": { + "sha": "52cdc221c9bd96052c372eb797b6e4660b16c20f", + "url": "https://api.github.com/repos/facebook/react/git/trees/52cdc221c9bd96052c372eb797b6e4660b16c20f" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/64ad2e25324016e94167d6d1d29f07e362fe221b", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Y2d0ACgkQWCcTbp05\ndTI1tRAAtLxkPWmdCW+SbjTAvKChiaNvcAop4zB6qxRq4TcUVZNRT7L2gH9d6Yi+\nT6ekMhqms26EMECnBx5Lh4CiK8E1IK5Cg7GomLjkracsl55ZKUB6AgcenmEayNY1\n0llW/izU5Wsp+rk7Ex50JHTEa9Bn6yzp67sfNKHw5sgZLsJixZqaWXIlOdxQcivQ\n8q89lP/xJ6d419iZ5YJd9Fvx0fX6vtM1KG5elZ4wY34YvLSdaLjZw5NANRcG7c6h\nt9n8rXw2szRqPKIPLpSKTM8p2mwohrT4HI4oPLhyRYn+v8vdkLRWeAM3as/z2GaU\n749++iW4D7uaJJWEUKuLMTGP6SKjK9q2s4YlAiTykXaVqui1GvTr404hp/IPsqk8\n93se1GhRZya+L1XNjK4C4eCbP8/mDuX/aCdIuEGy74LJC8qfMY4DInULzBIPaLv/\nviMsgDdUsmzESifzzgWe7b+M6UAeEAkfO0q8RuVV+r4X3hIPuYMAq0sXTAz02vRa\necyvRMCtO8e99q+gF2x0hPCNHOTXijzOfWQk0nZB11m/2tbSXMkXVYIuhxlzYpdO\nylzw7v6Oc1m2Es3uDW1zx0WRRytsZc699KJXY2xd4jiBPQSV/DYET90V0c0JA3yi\nfDsEib3b1ZcgvTPanuFhakY5+DPau5nH8Y813PwBfk0LpM+qUno=\n=Hqdz\n-----END PGP SIGNATURE-----", + "payload": "tree 52cdc221c9bd96052c372eb797b6e4660b16c20f\nparent 2aafbdf7718d1f25e1c69d738183db46aec09d12\nauthor eps1lon 1608047069 +0100\ncommitter eps1lon 1608047069 +0100\n\nMatch UX of Search\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/64ad2e25324016e94167d6d1d29f07e362fe221b", + "html_url": "https://github.com/facebook/react/commit/64ad2e25324016e94167d6d1d29f07e362fe221b", + "comments_url": "https://api.github.com/repos/facebook/react/commits/64ad2e25324016e94167d6d1d29f07e362fe221b/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "2aafbdf7718d1f25e1c69d738183db46aec09d12", + "url": "https://api.github.com/repos/facebook/react/commits/2aafbdf7718d1f25e1c69d738183db46aec09d12", + "html_url": "https://github.com/facebook/react/commit/2aafbdf7718d1f25e1c69d738183db46aec09d12" + } + ] + }, + { + "sha": "826993e4badfde5e687978798c286c44e7b7b45d", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjgyNjk5M2U0YmFkZmRlNWU2ODc5Nzg3OThjMjg2YzQ0ZTdiN2I0NWQ=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T15:48:24Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T15:48:24Z" + }, + "message": "Resolve todo about args copying", + "tree": { + "sha": "63a75c0b39b52f884be09989e2d6b9275838cf1a", + "url": "https://api.github.com/repos/facebook/react/git/trees/63a75c0b39b52f884be09989e2d6b9275838cf1a" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/826993e4badfde5e687978798c286c44e7b7b45d", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Y2tAACgkQWCcTbp05\ndTJK3g//W3CH0gs+ZWavsXv1J/Tt1bVuO9HQJ8rGNwCx+yN4zL0Jb22GM1wR3IOG\nZWA9uIlD6rIEWEuoNc/d4tft7kY9vGAn57xkIXaUcvcV7mUABxWYtTPPhRI7UVti\nThch5gu1OBFTB1ST7vtce3C03xw+wik/lto42baMGlSGzcRXqAFWvaSp/CtBznlU\nRtZOwuUHe6CMHUF/aU0+8YYrhmQcspB1qCAXwuwG+2wqtvbX2cO/uUzl85AAaIH9\niuXweHFIvlGKpJ+XUROf5SgdTAXiEyTdA2KPZCXldY9x5ONzJyG/8x5fw4MaMMk4\nE1gx5OqMmCMHh63LSCFoBb9TCSCwj8Qf/DKg39B2qu2BZPGjaDx1ZEXqi5dngWc1\n9VELKmceKmsTJR4kOIFYOUuRCKOdJb27kIw9AS63XuQYMSHNfCV2ZCViI4Qv4kvH\n647CkI5wfOTvbmXGTDZ0padwxJepbf0g2bMNdZATIcXOonGsqfynKXdurxAL9U+o\nLZqzUtfNZDjEpdWKZKMXc8K2JlteShdUHqbWwnVV9L/1Qz8nAjbaP0qtuCDa/VWQ\nC/PGnNTNSM5da0+Zy6ueQNkKCNp2/32f7CfhwvGad3/ULbSEzrbMqjSNumI6KlI8\nIr7IcZ1UBTeqtBPxwXUhCxw+DNKCgjatIx/Cpymn0tyKbTRcfRQ=\n=V8rz\n-----END PGP SIGNATURE-----", + "payload": "tree 63a75c0b39b52f884be09989e2d6b9275838cf1a\nparent 64ad2e25324016e94167d6d1d29f07e362fe221b\nauthor eps1lon 1608047304 +0100\ncommitter eps1lon 1608047304 +0100\n\nResolve todo about args copying\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/826993e4badfde5e687978798c286c44e7b7b45d", + "html_url": "https://github.com/facebook/react/commit/826993e4badfde5e687978798c286c44e7b7b45d", + "comments_url": "https://api.github.com/repos/facebook/react/commits/826993e4badfde5e687978798c286c44e7b7b45d/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "64ad2e25324016e94167d6d1d29f07e362fe221b", + "url": "https://api.github.com/repos/facebook/react/commits/64ad2e25324016e94167d6d1d29f07e362fe221b", + "html_url": "https://github.com/facebook/react/commit/64ad2e25324016e94167d6d1d29f07e362fe221b" + } + ] + }, + { + "sha": "eb9c4ec42dbe937b5dd93db06e5c74a41838763d", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmViOWM0ZWM0MmRiZTkzN2I1ZGQ5M2RiMDZlNWM3NGE0MTgzODc2M2Q=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T16:28:02Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T16:28:02Z" + }, + "message": "Remove excess vertical ruler if no errors are recognized", + "tree": { + "sha": "6d7cb67b555f98bfaf87efb7456c452880d8ec4c", + "url": "https://api.github.com/repos/facebook/react/git/trees/6d7cb67b555f98bfaf87efb7456c452880d8ec4c" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/eb9c4ec42dbe937b5dd93db06e5c74a41838763d", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Y5BIACgkQWCcTbp05\ndTKj1Q/7BUmr707T7dngikOz9wLtXw4pxZN+jmQD9UXAkDsrB+zaFirL62wgEXd+\n8Kh0SaA9XXzKi3nMqR6De0SuobiAgfQ/DTfF0gYbJ3Gx1djKqDAZBB90WNf+bjw4\nd5RuM3IBoJKrjywGUKRNLc7kVGhJ2UoGE7DkRIJX32ZWJcQ+q/6Cjoia4Tb2Ga39\n42eMcu7qwnxg1zkqZTLiIEfnesTxX6Z7gM9fSZEnLMKq8TWVGrjPBOxLNrUAbSmV\nAGiArudf+1Q1rDQnFZMnzGMNK/uBmgw6pbY/BdMgVTBfAxfTgsdp4OUHcQ+3wwS8\naO2JAID8l2mfOvFOEWgjGwAOV47F+62bwZIIyI6EWM/g23cT4zb7FnsA81siVoNx\n42+K12qs6sXkId1q6+oAxhHKhRY+ovbgEA0urKRrqp6tlyH5H8BG1QqqrYPfg77r\nJsWYJkOnu4GaeyK+iDKtBerH6tXW4oP7Qx7VvsQ0zf0XceeUUOBkstOtCBjGJGQP\nF5SBsJ/UOzb8P1Qt3zrrhvb1gu3BeK2m1G27GwGlgT1owgQALqqfkM6inqM4Pq3P\nRz0jyJkKnza3ehUFIa0+ewNvBI9iBMulPsB7g1MdBCzxTl6mmiS3C0TnuZ+eTS3r\n1qx0LSPPPWLZ8eLq9VxLP0tR+9b8NVIMAB3oTSE/UBhJYjGrZnk=\n=p40H\n-----END PGP SIGNATURE-----", + "payload": "tree 6d7cb67b555f98bfaf87efb7456c452880d8ec4c\nparent 826993e4badfde5e687978798c286c44e7b7b45d\nauthor eps1lon 1608049682 +0100\ncommitter eps1lon 1608049682 +0100\n\nRemove excess vertical ruler if no errors are recognized\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/eb9c4ec42dbe937b5dd93db06e5c74a41838763d", + "html_url": "https://github.com/facebook/react/commit/eb9c4ec42dbe937b5dd93db06e5c74a41838763d", + "comments_url": "https://api.github.com/repos/facebook/react/commits/eb9c4ec42dbe937b5dd93db06e5c74a41838763d/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "826993e4badfde5e687978798c286c44e7b7b45d", + "url": "https://api.github.com/repos/facebook/react/commits/826993e4badfde5e687978798c286c44e7b7b45d", + "html_url": "https://github.com/facebook/react/commit/826993e4badfde5e687978798c286c44e7b7b45d" + } + ] + }, + { + "sha": "f0a3ab3e79b711c52393513609bbaae80e694d0b", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmYwYTNhYjNlNzliNzExYzUyMzkzNTEzNjA5YmJhYWU4MGU2OTRkMGI=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T16:33:54Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T16:33:54Z" + }, + "message": "Fix icon alignment of errors/warnings in tree", + "tree": { + "sha": "8b0f52eb35480be9c9d4563f4e0fa4b3ae1b99ca", + "url": "https://api.github.com/repos/facebook/react/git/trees/8b0f52eb35480be9c9d4563f4e0fa4b3ae1b99ca" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/f0a3ab3e79b711c52393513609bbaae80e694d0b", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Y5XIACgkQWCcTbp05\ndTJjbQ/9EPdScIwYoLr7w7x+TyoYEKM+Tih70wb+oDBqUaPkumwrrbnd29IlZhKp\nooTQzR7b85mlROzCF0cXrvor6D/Hn73EHGibhua/sIQ4EXcGbqU3n9zaZj2wUmJA\nab/erpUfUYvnaZhfaRzNx0lB6DFxdD9paqiSMOgTFS34YXdfdKouRHZteFxuKLj6\nBuN7ujpCgdozmtczMKqnxR+KTbm8U2APYdeo2IULcsKQCr/6N5p49Ds3Q/0dX2H5\nu2JephNzEaz7v+HKglVLy/fvgXHOGSXp5t8gVRX6OtiYoiTIu7o/nTxnKsU0j0JT\nFJJoo+i6+AGlG5yMm7ar4O+pCDyOdAq2lu+a5iTA3cq9W6lq9vQWLfJjge3qaG26\nWOsv1Uha5lWovBDDNeJxXKcIp1VHlfYZ4kmW6MGdlpDaFSKjOml7hwA5TmCfCNHN\nXBv6h1D/wUd3+P/ZklrytRL8hogVqkOrc1fIQvhEsA2xgV/jsMpoAFK5nbkWv45Z\neguYuWcDcyMcm3lUklf/+IvdI2tP8PJhddcASqVyUydK9uPEzdO1N6Txn+PWqgp5\nsCyPFEVNcPSB33VuePyopYWt43vr9Fyfhp74rBtsq6FfVaQluxmP53qZeFWvAxRk\nZ6f9Uw3JDUsdfD5JV46H+xQEwHa/Bb3uUsQc+6WaB4io6cQMv+Y=\n=Ibdw\n-----END PGP SIGNATURE-----", + "payload": "tree 8b0f52eb35480be9c9d4563f4e0fa4b3ae1b99ca\nparent eb9c4ec42dbe937b5dd93db06e5c74a41838763d\nauthor eps1lon 1608050034 +0100\ncommitter eps1lon 1608050034 +0100\n\nFix icon alignment of errors/warnings in tree\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/f0a3ab3e79b711c52393513609bbaae80e694d0b", + "html_url": "https://github.com/facebook/react/commit/f0a3ab3e79b711c52393513609bbaae80e694d0b", + "comments_url": "https://api.github.com/repos/facebook/react/commits/f0a3ab3e79b711c52393513609bbaae80e694d0b/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "eb9c4ec42dbe937b5dd93db06e5c74a41838763d", + "url": "https://api.github.com/repos/facebook/react/commits/eb9c4ec42dbe937b5dd93db06e5c74a41838763d", + "html_url": "https://github.com/facebook/react/commit/eb9c4ec42dbe937b5dd93db06e5c74a41838763d" + } + ] + }, + { + "sha": "5b59bbce5d8055fbd7a616cfa64a4a03c685d21f", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjViNTliYmNlNWQ4MDU1ZmJkN2E2MTZjZmE2NGE0YTAzYzY4NWQyMWY=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T16:38:22Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T16:38:22Z" + }, + "message": "Fix warning text color in dark theme", + "tree": { + "sha": "c1b92ab905a0b3c3b89b0b235aa362844942e3ca", + "url": "https://api.github.com/repos/facebook/react/git/trees/c1b92ab905a0b3c3b89b0b235aa362844942e3ca" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/5b59bbce5d8055fbd7a616cfa64a4a03c685d21f", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Y5n4ACgkQWCcTbp05\ndTJFvw//e8DWTyCOl+Fd4RgWJeG195PkfM/69uzUNLb6zTEs2B3V5ysh9F1S+ukl\nS23vSCoJJvVO1Jik6ovubC89pD+UQHvqIC+hCsdqOLpkoME0b+YiAohuAzHQ00Me\n3/WxSRhm6NzbUbZzjdTMVPMKM7Gah74H+vWF/mlo40LJj1yyXMnOq1HXIsDE20q/\nn9i7qfp8n7DVCIL545NLrlTPi0d8fKOuDpA6r50fzM5Bu38s8eaHJeWzE2FvLBPi\nOmL+ozyJ4Ok+EcTlNaU2qRh6nWd3gi10QNX2LcN1wKaPldRZ1sYti6wwqYhj6bfZ\nCpnmkyfaX+gvu9O+ZI5Faq9tebyl0gkyp3NFbMBWMC+a2IcWPaVQd69uV3NPm23h\n1Y+QLdhX446AA6SMzGvucIeIzti8Wvv5CrAm0w7ahDUmXX8AAWYf4EDsZmM/IvAu\nEiB7ux8T1kLlp+wb/DZ2txOOOnZFOADQ3a/sDqnrvpBdHw6vXJ5aOXCeUxtGble3\n+RnD7eU31+55w+zsBavIF0E8fzAnGavOo4tUI1QaV5U4jc8OB/IlTa2YLSZtPhh4\nJyEF2wzsJKLkEqRZCueqXu/iyXW0kYRDIBs4JFpecM0DX1Ctkug/E+xGk7bf7wrk\ni2ywhbPVPBju5sQAIDCMMMG4PAFeqLpU3Z6NfBG92Hyp2JTG5DM=\n=jfgO\n-----END PGP SIGNATURE-----", + "payload": "tree c1b92ab905a0b3c3b89b0b235aa362844942e3ca\nparent f0a3ab3e79b711c52393513609bbaae80e694d0b\nauthor eps1lon 1608050302 +0100\ncommitter eps1lon 1608050302 +0100\n\nFix warning text color in dark theme\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/5b59bbce5d8055fbd7a616cfa64a4a03c685d21f", + "html_url": "https://github.com/facebook/react/commit/5b59bbce5d8055fbd7a616cfa64a4a03c685d21f", + "comments_url": "https://api.github.com/repos/facebook/react/commits/5b59bbce5d8055fbd7a616cfa64a4a03c685d21f/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "f0a3ab3e79b711c52393513609bbaae80e694d0b", + "url": "https://api.github.com/repos/facebook/react/commits/f0a3ab3e79b711c52393513609bbaae80e694d0b", + "html_url": "https://github.com/facebook/react/commit/f0a3ab3e79b711c52393513609bbaae80e694d0b" + } + ] + }, + { + "sha": "0ef80bce241c622a21d5da20b527822602599f36", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjBlZjgwYmNlMjQxYzYyMmEyMWQ1ZGEyMGI1Mjc4MjI2MDI1OTlmMzY=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T16:43:34Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T16:43:34Z" + }, + "message": "center icons with text instead of baseline", + "tree": { + "sha": "ca245927bedde6be191b2a88d2c43abd8e5726b0", + "url": "https://api.github.com/repos/facebook/react/git/trees/ca245927bedde6be191b2a88d2c43abd8e5726b0" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/0ef80bce241c622a21d5da20b527822602599f36", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Y57YACgkQWCcTbp05\ndTK/wQ//VvBmc5KzaqD9aEu62qlVXlWn7ew7ru4IswtIOBl1dedCCN6YNnQ5p0mY\naowLMxctoMWzUKt+Powy1tMksHanZvASW0/g+5n3arDP5l/Hj/+9LcTQoEz3Hx66\n68GodLiyvs/LrIhFHYnF9h3XkQkylVjwjxgshNWQI1muIdoPhSJvnyb3yxMpC2mm\no2WCdyW748HwuxSnjzw77S7PdctUoEG+TewTdndgVG120PHCFfuJjL8tEppZfy1w\n6wr6KQ3hISg6sh+CtbOTuolJARwgQzsadQnOu9r2yz/w/l3I8Yp+NylPycVp0FT2\nIENrCNo940g5VTxZshwIDho+HXhzhFZimuTGxY2WEmnLseCGDoZYRsadvQbaQEwW\ngODxyP0p6jOVWnt6aL5Jri7yFBajbFnV0ICOmnP8nLIwBjQABctf7CtKbatSNpWN\nCY3HZfAx2JpXLNZ+H0QhjN4An2ctp4aC/Mr2NGakLU1GYpup3c//ubhSv/xVSNuQ\nDbs0hnyyMVVhf6kPza2UJSPZrQbAESujTb616XsaNsih0TCch8Y3HWUpE0+TFbgw\nC7eZ2JRxc1nwzWLRmX9qC9XYdbXcrcPT080bwQvTaappPjLyUfcx/pJydqXwPSpS\ntsZVhmVs4InghhBOC7/l1kYJAgjCsjUjk00HQNY1mvwBm0k5tLE=\n=cAms\n-----END PGP SIGNATURE-----", + "payload": "tree ca245927bedde6be191b2a88d2c43abd8e5726b0\nparent 5b59bbce5d8055fbd7a616cfa64a4a03c685d21f\nauthor eps1lon 1608050614 +0100\ncommitter eps1lon 1608050614 +0100\n\ncenter icons with text instead of baseline\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/0ef80bce241c622a21d5da20b527822602599f36", + "html_url": "https://github.com/facebook/react/commit/0ef80bce241c622a21d5da20b527822602599f36", + "comments_url": "https://api.github.com/repos/facebook/react/commits/0ef80bce241c622a21d5da20b527822602599f36/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "5b59bbce5d8055fbd7a616cfa64a4a03c685d21f", + "url": "https://api.github.com/repos/facebook/react/commits/5b59bbce5d8055fbd7a616cfa64a4a03c685d21f", + "html_url": "https://github.com/facebook/react/commit/5b59bbce5d8055fbd7a616cfa64a4a03c685d21f" + } + ] + }, + { + "sha": "61924778be0a4934e02e6c214ea3c676868f95de", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjYxOTI0Nzc4YmUwYTQ5MzRlMDJlNmMyMTRlYTNjNjc2ODY4Zjk1ZGU=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T17:29:00Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-15T17:29:00Z" + }, + "message": "Clear errorsAndWarnings when elements are removed", + "tree": { + "sha": "5138be93763993cd4932b9a74c9d00d65483d4ce", + "url": "https://api.github.com/repos/facebook/react/git/trees/5138be93763993cd4932b9a74c9d00d65483d4ce" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/61924778be0a4934e02e6c214ea3c676868f95de", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Y8lwACgkQWCcTbp05\ndTJCuA//TvBpO/dJ+/NQkIhL0UpeNdgsxogkEOgxHtAN8kqt/OtPnFbqG8ClChyM\ns/1uqTTtBHuStbrcUsTUuBEjNZkCeyifrSzRbkDLkFtdGYVAO6u0xFDm3fAk9bGs\nxZQzzSKMselwlHMljsmvWQDnz3AYuQyx553dgzNCLQAVrPsoL3fth7Wso2qLkI70\n3fcgdzRLvmczlXKBgUDyrspsX0GIxlYR+B42LmTWLSjqaBoa3KZXtIVHu488K0w6\nrY0XuSLno68ZZfERPeLE+66dY3SIfWYv8LtMRANPYE3l+UT0gkrm2GhtymRQX60j\neNpD9CK999oNiBKja7yHVc02xA07MdDCaqzGCdyEwGBur7L4Z/gdgNz95fOoIwGc\nYk+j+MTiU5NSYYbg6yb07X4ebHr1eELgVdZHRlUPUvNfK3i1QhoVYCSbRKhXNyzU\nW+mm/7cRyPIPJ0hEag0MlbqQIHNHZSs3rcODJzpm9EzdqKzO4w+uqak3/N0Gw71g\nVoToisTTVrP2Dorn8U4F6KKrgo+XZU19gPINqnZ2SSHlbeG0eliSLDIYN+B/80kB\nnnmQGL+5oHnZqc3ec1QCOe+srK8YL+DuTeiiYn8gArvVeNgq3KuuLFPRSHkltdAa\nPT8r7rVyVmCaRT80RvSpsoZDbUkdWoTha2+P1+LjOrWLZySZLMo=\n=aj/8\n-----END PGP SIGNATURE-----", + "payload": "tree 5138be93763993cd4932b9a74c9d00d65483d4ce\nparent 0ef80bce241c622a21d5da20b527822602599f36\nauthor eps1lon 1608053340 +0100\ncommitter eps1lon 1608053340 +0100\n\nClear errorsAndWarnings when elements are removed\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/61924778be0a4934e02e6c214ea3c676868f95de", + "html_url": "https://github.com/facebook/react/commit/61924778be0a4934e02e6c214ea3c676868f95de", + "comments_url": "https://api.github.com/repos/facebook/react/commits/61924778be0a4934e02e6c214ea3c676868f95de/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "0ef80bce241c622a21d5da20b527822602599f36", + "url": "https://api.github.com/repos/facebook/react/commits/0ef80bce241c622a21d5da20b527822602599f36", + "html_url": "https://github.com/facebook/react/commit/0ef80bce241c622a21d5da20b527822602599f36" + } + ] + }, + { + "sha": "6e57b4d1798f031a844fd960038cacf29dc0b534", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjZlNTdiNGQxNzk4ZjAzMWE4NDRmZDk2MDAzOGNhY2YyOWRjMGI1MzQ=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-15T18:24:41Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-15T18:24:41Z" + }, + "message": "Tweaked inline element style for warning/error icons", + "tree": { + "sha": "219cb4c1ffada21259876d390df1a85767481617", + "url": "https://api.github.com/repos/facebook/react/git/trees/219cb4c1ffada21259876d390df1a85767481617" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/6e57b4d1798f031a844fd960038cacf29dc0b534", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/6e57b4d1798f031a844fd960038cacf29dc0b534", + "html_url": "https://github.com/facebook/react/commit/6e57b4d1798f031a844fd960038cacf29dc0b534", + "comments_url": "https://api.github.com/repos/facebook/react/commits/6e57b4d1798f031a844fd960038cacf29dc0b534/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "61924778be0a4934e02e6c214ea3c676868f95de", + "url": "https://api.github.com/repos/facebook/react/commits/61924778be0a4934e02e6c214ea3c676868f95de", + "html_url": "https://github.com/facebook/react/commit/61924778be0a4934e02e6c214ea3c676868f95de" + } + ] + } +] \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/clients/pull_request_commits_page2.json b/src/test/resources/com/spotify/github/v3/clients/pull_request_commits_page2.json new file mode 100644 index 00000000..1db28543 --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/clients/pull_request_commits_page2.json @@ -0,0 +1,1787 @@ +[ + { + "sha": "2df0740ec43c3d3ea6cb93dfc2808398a3d06c1e", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjJkZjA3NDBlYzQzYzNkM2VhNmNiOTNkZmMyODA4Mzk4YTNkMDZjMWU=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-15T20:20:16Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-15T20:20:16Z" + }, + "message": "Fixed minor regression in Element styles", + "tree": { + "sha": "e7862387c55b068011874af57595c12b4a21dc16", + "url": "https://api.github.com/repos/facebook/react/git/trees/e7862387c55b068011874af57595c12b4a21dc16" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/2df0740ec43c3d3ea6cb93dfc2808398a3d06c1e", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/2df0740ec43c3d3ea6cb93dfc2808398a3d06c1e", + "html_url": "https://github.com/facebook/react/commit/2df0740ec43c3d3ea6cb93dfc2808398a3d06c1e", + "comments_url": "https://api.github.com/repos/facebook/react/commits/2df0740ec43c3d3ea6cb93dfc2808398a3d06c1e/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "6e57b4d1798f031a844fd960038cacf29dc0b534", + "url": "https://api.github.com/repos/facebook/react/commits/6e57b4d1798f031a844fd960038cacf29dc0b534", + "html_url": "https://github.com/facebook/react/commit/6e57b4d1798f031a844fd960038cacf29dc0b534" + } + ] + }, + { + "sha": "52f0494e44d7c01f6f1c53f3c5dce83e07d27aa6", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjUyZjA0OTRlNDRkN2MwMWY2ZjFjNTNmM2M1ZGNlODNlMDdkMjdhYTY=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-15T20:20:26Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-15T20:20:26Z" + }, + "message": "Split errors and warnings into separate panels", + "tree": { + "sha": "1ff469cd73189d817cb4b60faecce7aac0fd64ad", + "url": "https://api.github.com/repos/facebook/react/git/trees/1ff469cd73189d817cb4b60faecce7aac0fd64ad" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/52f0494e44d7c01f6f1c53f3c5dce83e07d27aa6", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/52f0494e44d7c01f6f1c53f3c5dce83e07d27aa6", + "html_url": "https://github.com/facebook/react/commit/52f0494e44d7c01f6f1c53f3c5dce83e07d27aa6", + "comments_url": "https://api.github.com/repos/facebook/react/commits/52f0494e44d7c01f6f1c53f3c5dce83e07d27aa6/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "2df0740ec43c3d3ea6cb93dfc2808398a3d06c1e", + "url": "https://api.github.com/repos/facebook/react/commits/2df0740ec43c3d3ea6cb93dfc2808398a3d06c1e", + "html_url": "https://github.com/facebook/react/commit/2df0740ec43c3d3ea6cb93dfc2808398a3d06c1e" + } + ] + }, + { + "sha": "d64023c01cc983b34cf50617c8c9cc6d76ab7311", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmQ2NDAyM2MwMWNjOTgzYjM0Y2Y1MDYxN2M4YzljYzZkNzZhYjczMTE=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T07:03:50Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T08:49:16Z" + }, + "message": "Implement new message format\n\nWhen flushing messages we use a new type of operation instead that only contains the number of warnings/errors.\nThe messages itself are only sent as part of the inspectElement event.\nAlready implemented a mapping from the message to a unique id.\nThough I'm not quite sure why we wanted to do that.\nDid we want to send the message only once and then ids if it repeats?", + "tree": { + "sha": "5d11999c088b1514c751acdd60d362394b05dce9", + "url": "https://api.github.com/repos/facebook/react/git/trees/5d11999c088b1514c751acdd60d362394b05dce9" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/d64023c01cc983b34cf50617c8c9cc6d76ab7311", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/ZyhAACgkQWCcTbp05\ndTKtkw//aN7ZYyw8dLTX9JwE0ZbVxeToE0jRmn338ko2+h1P/WAZoztmnuELEoae\nI/STR32YFc4w8xkl2cd1sNRIKnCestfn9KH6Uj787UhrD23IrtFFnpf2EVnr7qPs\nf92akXGTCIuVBAMIFgMypQvAbF4E+fZ71MWS5K/xPMTLyUCcsE5clFKIKRofXoe2\nXPmEuz21fCdr7IPbFx65h9EMDDCM8H/rXYEN8fpFCMgnKmQUz95dF4cgvDqcpTX7\nOLYTMVlhoCP78+CXVC1JlASK4dZs3cq2bvqGL6lTDEncG7s8PHz7xU5ivg/DveHI\nhMeQgnz5re7W6fgDPexoJ5EnUASN0k5AZZla2XkTN/BL/+XHwpWw/GtlftwskaWJ\nT61ul0TIXtCwTW8Hodzeo2iOdvUXygs7ooPMkantnXJi8C/rmhn83pIUd1cryoyU\nECgsirEAbweJUwY0w5RWza+84I5MGwKFuceRII0/iE7t+eR/LZajBtrM9LgZ9RyC\nJBqqUhgTNVfq4Uw8SP4SqR/tk5DpcZZoEF5oWsnf6TLHejbg0TUOTtsf0DrqifDM\nwtbw15N7og/7a3NoJ0EYwJLziBiOzSWnrGd2EI4785dRAJQ2vnjVZE4wQrLBkXpN\nL0x0HknGffHXRlBmJbwz7ctvzAny5cECkr7HMroK+PXkfTe9PLA=\n=3VlL\n-----END PGP SIGNATURE-----", + "payload": "tree 5d11999c088b1514c751acdd60d362394b05dce9\nparent 52f0494e44d7c01f6f1c53f3c5dce83e07d27aa6\nauthor eps1lon 1608102230 +0100\ncommitter eps1lon 1608108556 +0100\n\nImplement new message format\n\nWhen flushing messages we use a new type of operation instead that only contains the number of warnings/errors.\nThe messages itself are only sent as part of the inspectElement event.\nAlready implemented a mapping from the message to a unique id.\nThough I'm not quite sure why we wanted to do that.\nDid we want to send the message only once and then ids if it repeats?\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/d64023c01cc983b34cf50617c8c9cc6d76ab7311", + "html_url": "https://github.com/facebook/react/commit/d64023c01cc983b34cf50617c8c9cc6d76ab7311", + "comments_url": "https://api.github.com/repos/facebook/react/commits/d64023c01cc983b34cf50617c8c9cc6d76ab7311/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "52f0494e44d7c01f6f1c53f3c5dce83e07d27aa6", + "url": "https://api.github.com/repos/facebook/react/commits/52f0494e44d7c01f6f1c53f3c5dce83e07d27aa6", + "html_url": "https://github.com/facebook/react/commit/52f0494e44d7c01f6f1c53f3c5dce83e07d27aa6" + } + ] + }, + { + "sha": "1bb99d9cc10270abb6136d6b1695b3e965967e5f", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjFiYjk5ZDljYzEwMjcwYWJiNjEzNmQ2YjE2OTViM2U5NjU5NjdlNWY=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T07:22:29Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T08:49:20Z" + }, + "message": "Reflect error/warning updates in tree when cleared", + "tree": { + "sha": "e520ca7ee748280f641ea1cac84a505321c30acd", + "url": "https://api.github.com/repos/facebook/react/git/trees/e520ca7ee748280f641ea1cac84a505321c30acd" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/1bb99d9cc10270abb6136d6b1695b3e965967e5f", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/ZyhAACgkQWCcTbp05\ndTIjmQ//Ub/9mVc0egLIGlZxHFtVPJXLsOQrzTiK1KpOewwe03oRCN/FQeQKz5Ds\nZGxy8Z8ztlVWizSEyNF2Ix5vJR1PCNKl0k3HS0Mzuhl5AYOURR97xzaawtrFqJ9n\nfkIi3emDTaOWd/iaiwr+dAU646vSpzaL/2KJyhA772FhGj3Q+eNER+qXMlO3NA1V\nqLBld4tDeYB5eBXnlXxIdxZtNVyqYTzBWWzXcIp9VWNSjYAbmgsQLKlsHNb7cF2p\nrdQoiUE8eMtwtMadu++zw4AteWO/J7azizQEFBHsFvp7Qi83+Keok8tWOAwPKAzA\nzRMhCtua7fxTDCMYii1zzyT+Vn1EMOD51RE/ZtnazHr8t/UKQkUVZnN0sejGA/Bf\nRTPcVHtNuPCx7uA296VQ4W7zK15z8y3ddfwwvFgLWg/x8VWK9OHs+n1oMjLyzvPn\n/Hny++5cJlYpAXKv0qemHg5WILeYtnv9CE5c+yFMDk6PUkLsAEYL3y3uhOp2O+4l\nPL1gskMONzVqwJD85hXqda+MHRTN/S15a0oIN4YboN/ZM9u0oAafcqVqK/48f/kt\nh7KJXVS7JF0gRXrDZ/wBt9FwdrXotewbD39PU/ZGynmay+NKX1RGNpuFnzyb5GFc\nAVFbQhim8N1+hYd6akkTqOUt7ro9fjQ2vAFxz2W5bzmB6OqjBq8=\n=ezct\n-----END PGP SIGNATURE-----", + "payload": "tree e520ca7ee748280f641ea1cac84a505321c30acd\nparent d64023c01cc983b34cf50617c8c9cc6d76ab7311\nauthor eps1lon 1608103349 +0100\ncommitter eps1lon 1608108560 +0100\n\nReflect error/warning updates in tree when cleared\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/1bb99d9cc10270abb6136d6b1695b3e965967e5f", + "html_url": "https://github.com/facebook/react/commit/1bb99d9cc10270abb6136d6b1695b3e965967e5f", + "comments_url": "https://api.github.com/repos/facebook/react/commits/1bb99d9cc10270abb6136d6b1695b3e965967e5f/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "d64023c01cc983b34cf50617c8c9cc6d76ab7311", + "url": "https://api.github.com/repos/facebook/react/commits/d64023c01cc983b34cf50617c8c9cc6d76ab7311", + "html_url": "https://github.com/facebook/react/commit/d64023c01cc983b34cf50617c8c9cc6d76ab7311" + } + ] + }, + { + "sha": "c197030fe4a3299e0e9c6fa0b6374dff1cabe2fe", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmMxOTcwMzBmZTRhMzI5OWUwZTljNmZhMGI2Mzc0ZGZmMWNhYmUyZmU=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T08:43:19Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T08:49:20Z" + }, + "message": "Fix inspectedElement not updating on error/warnings update", + "tree": { + "sha": "96b7b2c6935b35a748e9fcdfda68c69f14c2c72d", + "url": "https://api.github.com/repos/facebook/react/git/trees/96b7b2c6935b35a748e9fcdfda68c69f14c2c72d" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/c197030fe4a3299e0e9c6fa0b6374dff1cabe2fe", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/ZyhAACgkQWCcTbp05\ndTJCpw//Y/w8YH3ccCIScyvJhunzc81mj9Gv3tsuDCO7d2q2tJMzpNvRmqZsdWjU\n5QE4lQfwjOBFXhznEwcgt8oVHIj4cwSr/+0imu1TpuNvWOzggf9zonFuS/wTaGkz\nKN7sgZgArwes8NtsmlbnJ3Yr2DUkfeysrswLhDk6YTDjwMBAtcM9iqsK19ZXat0G\n1XKG8Ks7Zk4oMME7uNlY7gn3z46FmnXWwEiMrLiOKnCDLaVgKBA5y0kSd3UEE+Qj\nNmfEohYq9SJTE3fCbKDgqoFGv0eCtYfSoxcmlts3N7KHB9gkxjWQbTQ+2EHdRUow\n2gjFSDukKeTC2BnowiOMjkWcM9ypBobtl3XJUcVqfl1KNNKY6p8VbKdBAvTMZS4/\nYqRBYsnfIv4f2CrguJv9ONcw+bCqgYYxHvE9g0cpVm5NPEpxSEkPN2SoG9bJPh9E\nnRfZ2pUzkzguXLpjOof5hCImw5R4tbdDFbgXqghWszMKG/F/rMO4Lwmt0fmfW8VW\nxmKkbvor/H02ImhHZSTwU9PLp+KpH92B1AOMa68DZbdp9UACj5EnmyudRJDwEa4V\nG/4WH0EShkxDYoJNSJiYY/9i5aE8ZOQz2mNPGUm/wj23OoCnim1Tt3uzWWouJDj3\nBJrGK3k3KQb+eCxoCO+QehpUGVeO3ApQFd5xG+TawgZij7kZWNA=\n=cIY7\n-----END PGP SIGNATURE-----", + "payload": "tree 96b7b2c6935b35a748e9fcdfda68c69f14c2c72d\nparent 1bb99d9cc10270abb6136d6b1695b3e965967e5f\nauthor eps1lon 1608108199 +0100\ncommitter eps1lon 1608108560 +0100\n\nFix inspectedElement not updating on error/warnings update\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/c197030fe4a3299e0e9c6fa0b6374dff1cabe2fe", + "html_url": "https://github.com/facebook/react/commit/c197030fe4a3299e0e9c6fa0b6374dff1cabe2fe", + "comments_url": "https://api.github.com/repos/facebook/react/commits/c197030fe4a3299e0e9c6fa0b6374dff1cabe2fe/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "1bb99d9cc10270abb6136d6b1695b3e965967e5f", + "url": "https://api.github.com/repos/facebook/react/commits/1bb99d9cc10270abb6136d6b1695b3e965967e5f", + "html_url": "https://github.com/facebook/react/commit/1bb99d9cc10270abb6136d6b1695b3e965967e5f" + } + ] + }, + { + "sha": "2a3423f946a958590950ec426d2bc3cc894c0018", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjJhMzQyM2Y5NDZhOTU4NTkwOTUwZWM0MjZkMmJjM2NjODk0YzAwMTg=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T08:55:45Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T08:55:45Z" + }, + "message": "fix minor flow issues", + "tree": { + "sha": "72e50d7d7bde03ef6c159bc9b0ca64187b2c63ff", + "url": "https://api.github.com/repos/facebook/react/git/trees/72e50d7d7bde03ef6c159bc9b0ca64187b2c63ff" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/2a3423f946a958590950ec426d2bc3cc894c0018", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Zy5EACgkQWCcTbp05\ndTJzLhAAlkcQcp6hnzKXEoe1w+Mzneu7DWqO5Y7QX8f/e27+2xa6wsxq3fpZqApb\nlsgpoNbqM3Gt3JWIkAyOls7cMTsOa1F3FRlSZnwJCpWM902Ld+QhMSX24MTGJWla\nNcGO2B/BsezVlGS2PH++G2X64kThfV2a7myjvKYVbqrkLRB/1gY2YhaT7LdOFpkA\nJ73NAOBijvLOrcY2fUAMx2gKq5lbEK+WZdJAp7tnI4ND4XuR0fr+WIS8XyAwu/mP\nMn3VV97qh1+Wz+Wh8Q1cjzKUuhkc/mZQZbsSwLbnrstKlT+gyLwHIcEjlyU8nDER\nAMMJOB4I3Tq1xFUq1JqBapz4vqd9SSkngCwxMrk+CSihe90IIzC/YyLU1nGKYtdO\njFhYiquYKhXxdpBOGDLk6kMk7zUdvj/IC1iHh4IhNrBKnBrv2EDdis0XPumLOoeV\nFqI/xZsJZLika6SmZg2VgQvpF9JiHrKgiycjA/hQT25XK9juQkfKBs7Dc7/Olzt3\n2p9revQi9u3Pbv6Hqufhf0I9J1wW5YI3Q+Pqp+bebEE7xtDybFKOBCIxXflg0DYD\nx7s4HYQgWZAqxL/7IMAn/SMvW3b3Oy5FaqD24oLml/2kjmR1vNjHDDC4vWiDPV/M\n79FQrJV9IrWhpOp0XBaM+g5ZTVMpwzuTqDvRt5zi2ufKX+e8S5w=\n=dcfm\n-----END PGP SIGNATURE-----", + "payload": "tree 72e50d7d7bde03ef6c159bc9b0ca64187b2c63ff\nparent c197030fe4a3299e0e9c6fa0b6374dff1cabe2fe\nauthor eps1lon 1608108945 +0100\ncommitter eps1lon 1608108945 +0100\n\nfix minor flow issues\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/2a3423f946a958590950ec426d2bc3cc894c0018", + "html_url": "https://github.com/facebook/react/commit/2a3423f946a958590950ec426d2bc3cc894c0018", + "comments_url": "https://api.github.com/repos/facebook/react/commits/2a3423f946a958590950ec426d2bc3cc894c0018/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "c197030fe4a3299e0e9c6fa0b6374dff1cabe2fe", + "url": "https://api.github.com/repos/facebook/react/commits/c197030fe4a3299e0e9c6fa0b6374dff1cabe2fe", + "html_url": "https://github.com/facebook/react/commit/c197030fe4a3299e0e9c6fa0b6374dff1cabe2fe" + } + ] + }, + { + "sha": "9df59c6051258d332f4c35925c0da1dc9fa8ff4c", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjlkZjU5YzYwNTEyNThkMzMyZjRjMzU5MjVjMGRhMWRjOWZhOGZmNGM=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T09:14:35Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T09:14:35Z" + }, + "message": "Fix style regressions during rebase", + "tree": { + "sha": "e8cb78c99a9b7019210443dd8acf7f0e5cd69912", + "url": "https://api.github.com/repos/facebook/react/git/trees/e8cb78c99a9b7019210443dd8acf7f0e5cd69912" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/9df59c6051258d332f4c35925c0da1dc9fa8ff4c", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Zz/sACgkQWCcTbp05\ndTLYtg/+LhNbOw2W6JV0P0pZ1pDZAMii/vkSid5ZxWOqpDyKSCqMPf6FBjJAOPNq\nyHm8Gul9xoY8dZcdLnvU8jCC76zm6Isuo++5eMNIvfimNidfnvUUxImet9bvMoqO\nA4r1/Ebo3/biKfquUAONELbF4OTGuIA5W/TNEYKiFG0/0nENAFUhQKgV3gGqlPfi\nlmtt2ARmJQeBFIIPxiYAnem9UBFwm23SksbpAThmqX6x91vwf5tjzN6hHIlUKX9Z\n2rjy4XG5wa29VINfypYmuVAM7tbQmTP3u9TY3IjXPeBapfCulCRFW+aObP27QIO/\nc7+kyjeKpS4pjByBF7yYYg+pX9GoR1oQpzG7zTiksjCo4d0pHwkrsdZgwtvOwAqC\nwlB1ZEhHXezAi8f3VqNlTeLfrdc96xDaWH5g1beVVV2bJE3jpqDiGQQIJWBLRjFU\nuyhwKePnbWEcWVxe3L7K1/aWo2L0X8mcD1W0LeFfbaCnp3eph2MgKxNJzaIayNho\ndPGcl41yDlGGplB2KTKrWBvPPRIHtDteHQVE6YCfbGW4y9SHWi0olkSBv/f2VQlc\nwMrU6wr1YjZMXPLKakcegPj9JwdQJezj2Gk5a8c5IWzfAWJZfPX1cFcg1s90Owih\ne6zuE7ZI0bT4C1VgCrVA3RJ1C/lzm2wjL9sdJNN0lLfcoBnVBJ8=\n=zIS2\n-----END PGP SIGNATURE-----", + "payload": "tree e8cb78c99a9b7019210443dd8acf7f0e5cd69912\nparent 2a3423f946a958590950ec426d2bc3cc894c0018\nauthor eps1lon 1608110075 +0100\ncommitter eps1lon 1608110075 +0100\n\nFix style regressions during rebase\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/9df59c6051258d332f4c35925c0da1dc9fa8ff4c", + "html_url": "https://github.com/facebook/react/commit/9df59c6051258d332f4c35925c0da1dc9fa8ff4c", + "comments_url": "https://api.github.com/repos/facebook/react/commits/9df59c6051258d332f4c35925c0da1dc9fa8ff4c/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "2a3423f946a958590950ec426d2bc3cc894c0018", + "url": "https://api.github.com/repos/facebook/react/commits/2a3423f946a958590950ec426d2bc3cc894c0018", + "html_url": "https://github.com/facebook/react/commit/2a3423f946a958590950ec426d2bc3cc894c0018" + } + ] + }, + { + "sha": "bdf5d0ea634b0165887e08adc8ffc34375bc66e7", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmJkZjVkMGVhNjM0YjAxNjU4ODdlMDhhZGM4ZmZjMzQzNzViYzY2ZTc=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T09:18:45Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T09:18:45Z" + }, + "message": "Move Stepper UX to end of toolbar", + "tree": { + "sha": "0fad1eaf8a511cec14fb4a7b54241a6c4d97370f", + "url": "https://api.github.com/repos/facebook/react/git/trees/0fad1eaf8a511cec14fb4a7b54241a6c4d97370f" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/bdf5d0ea634b0165887e08adc8ffc34375bc66e7", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Z0PUACgkQWCcTbp05\ndTKQehAApdTy/tmgf9z9upZzsZNXxCu3UhNFtBpxQPW0299bZDTick+Oa+0pObhR\nbo5Ao9X4jSCgF/2A8caIo1armEpKodmPhsfdd/0hWi4k8iylYYDjk5X2onx2gQ3n\nGpuFi6z3A7WnfaB3DlNplkaO7xpdByxFbyYtW1uh4S0rnK/Kn5OFVvfJpLQIAFFA\nokkhNJLKns8DoBu4qi4jKwr+RwQR/VqtNbMOiZkdVeRdAYFfNFyAuiiZ6ZropRJ7\nwuURY6XrSLe4pU1RvHvlzf4dKY6ScgckJNsSbhzDhdynlwOn/ycPCW3kwy/P7MrN\noBRGfpq7DsFjrxtegqgIlBufCtif/5fgrBLtE5dH/0TexsxJXInPKwwmdQIu+MJi\nVjDcSRmTnP3aA8jGwKO/tWhnDwgkFIDS4y6JSfAJBMAzP0szWy1Jz91YbvXYo3I/\np6m1vfiHNByzon/ejZFiVVa0L2t/NuodLov9ctwmyTdwUdAp5bvWaLkkimM9CiH3\nULL9U7i1oKmzm7nNxEfl33WFAO/dpy4Xt2ZpS5QCtcKYPV1YMEUNy85kex0K6K9n\n/zh2BAXeHMyDAApqVgxLQl208ecK2LYdtqG5UDmwJuCcEcQEHNtZx8EkGoB08F6M\nR9KMuwNka7uTKDNZQXFT38sB6cgTc3/Exwcd4/9dkx93rfSblJA=\n=fbRE\n-----END PGP SIGNATURE-----", + "payload": "tree 0fad1eaf8a511cec14fb4a7b54241a6c4d97370f\nparent 9df59c6051258d332f4c35925c0da1dc9fa8ff4c\nauthor eps1lon 1608110325 +0100\ncommitter eps1lon 1608110325 +0100\n\nMove Stepper UX to end of toolbar\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/bdf5d0ea634b0165887e08adc8ffc34375bc66e7", + "html_url": "https://github.com/facebook/react/commit/bdf5d0ea634b0165887e08adc8ffc34375bc66e7", + "comments_url": "https://api.github.com/repos/facebook/react/commits/bdf5d0ea634b0165887e08adc8ffc34375bc66e7/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "9df59c6051258d332f4c35925c0da1dc9fa8ff4c", + "url": "https://api.github.com/repos/facebook/react/commits/9df59c6051258d332f4c35925c0da1dc9fa8ff4c", + "html_url": "https://github.com/facebook/react/commit/9df59c6051258d332f4c35925c0da1dc9fa8ff4c" + } + ] + }, + { + "sha": "3a37795a9e8a696a86a761a7424dc6b35a973909", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjNhMzc3OTVhOWU4YTY5NmE4NmE3NjFhNzQyNGRjNmIzNWE5NzM5MDk=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T09:20:24Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T09:20:24Z" + }, + "message": "Cleanup WIP artifacts", + "tree": { + "sha": "0da870f061b8b16968020e2ec7c7021d6d6d967c", + "url": "https://api.github.com/repos/facebook/react/git/trees/0da870f061b8b16968020e2ec7c7021d6d6d967c" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/3a37795a9e8a696a86a761a7424dc6b35a973909", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Z0VgACgkQWCcTbp05\ndTKVixAAsAON+H3axT8nTnwB7CAjOSkreF6J9Lwla6iDLx/QFQv8pG0uU5kNDPZB\nDD3gWt0QGRgVbotaTapyl5mqG7o3JGRMjAnIB4zMcug4Dz8lqLXlZrqxkxIdcugE\nc1FHwEp1QRJCJqtPfy7g7PqlaUTGQeT+c+wAQMJKMKoVkr7iyKRGq0i+PReBwWp2\nDKAEre+xQwwVq+6ZpuJwQVlm8lY7Tf1lAGVuL15ITUEsoZ0Vf2CFmxfE1ZsSEs42\n+EjerimduqJ4OaJ0GXZEciBmayZGSnU3NIiXgx7z6jYzwES57EFU1MTGG2tS8a9j\na6bmr6aCXl3lGi3Zzg5W+qPYkEukaIinaaghP70kjgxD9T4pxb6+cjxN2XyJhQuf\n/eW3gu+fxb4GDVqt4L+fn26qzJXW2YQBz3CkSkorsmyG4ouJpN3Qg+huhZI62hCx\ntAagzgmeUeNRPpVqaG6mAxa3iN6/q3Zu+Gmmh/khuIvTQNBuUBwu98rxv2ojLlga\nJHl8jqTuYTZbHr/m1SfSI7DXWxjEbgDYUWTlW/kEXlcXyHXk5KWY7+tNUh1Q7rId\nJ3bKVQbh6odxIsKgElensWWvb+2ykl7jtPCSNo4VWW+AUTrCaCBK/dcUfzHZQGkc\nEnfzbyxKpFajirFdibQL0tisGZ8k00v6Y5bPclMKFmirKoeOk70=\n=qHcQ\n-----END PGP SIGNATURE-----", + "payload": "tree 0da870f061b8b16968020e2ec7c7021d6d6d967c\nparent bdf5d0ea634b0165887e08adc8ffc34375bc66e7\nauthor eps1lon 1608110424 +0100\ncommitter eps1lon 1608110424 +0100\n\nCleanup WIP artifacts\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/3a37795a9e8a696a86a761a7424dc6b35a973909", + "html_url": "https://github.com/facebook/react/commit/3a37795a9e8a696a86a761a7424dc6b35a973909", + "comments_url": "https://api.github.com/repos/facebook/react/commits/3a37795a9e8a696a86a761a7424dc6b35a973909/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "bdf5d0ea634b0165887e08adc8ffc34375bc66e7", + "url": "https://api.github.com/repos/facebook/react/commits/bdf5d0ea634b0165887e08adc8ffc34375bc66e7", + "html_url": "https://github.com/facebook/react/commit/bdf5d0ea634b0165887e08adc8ffc34375bc66e7" + } + ] + }, + { + "sha": "91366be564aab76c4c8328eae7972844e4d244e6", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjkxMzY2YmU1NjRhYWI3NmM0YzgzMjhlYWU3OTcyODQ0ZTRkMjQ0ZTY=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T09:50:15Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T09:50:15Z" + }, + "message": "Add tally of errors/warnings", + "tree": { + "sha": "e7a71825c01bc86dc7fe01eed981e16f743eb766", + "url": "https://api.github.com/repos/facebook/react/git/trees/e7a71825c01bc86dc7fe01eed981e16f743eb766" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/91366be564aab76c4c8328eae7972844e4d244e6", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Z2FcACgkQWCcTbp05\ndTJ82hAAsuLBKt9Pj3Vdx+QBExmmJYhI2l3s/3yux9X91J/BW5yUHaoy5p8vQymm\nzwn3QJtI0hJxs++UGRv2F3a+EGvUFmdQe2kkmKE/pBuS82OEfxO3bPJ40ouzw2/B\noUCsIGkM8uEc1+ODE/qGVE0oWXDC737tWJow08kt9cqwaDk1ScwAb61uTqShhJyK\nNDy0QOpv+fWu7ZREtpEXFGtr1cnq1Q1c2uwU+T2J8FivZ4KLemumduYF1l8hZy/b\nw1Br3mPBHQoYQ5Etyd4Z3lxWQxPOihJOez9S9+sdGF3n2k32jLzy/tUUUAbNnNGv\nlsGm5kJjYiRYQq+NaSYJz074yu4ke3XSMLMp1TL9JPGXygIyKVJC9SHMQJtYdqec\nVqK1hC2wE12oguL9Z4oia281vXuDTd9Xoe2d8+hMqk0LQuz3ro2VefBJp/pjtkvv\nWn/0hE6sCJpEhQBnZgUOjft5I6phZjqm0YuE7nN8MAFBI5duA5UMBHe9ntKtr4fp\nGeC/W0bNQebLgLuYPmXW4QU0Nx7yZblxwux1d7uvD3OYRShiRGRH6gnYZTK8kTvm\nUAyEFggLY2f0pHWllP01VwC+0bH6v8oQxeWxAgTbtXuvz9wXUksS5gcrWH6sG9Sx\nKCufiwzvgcB5DkMtkhid6ZWdCpaIeRql39K+Snll7PilLgJwrwg=\n=e6jT\n-----END PGP SIGNATURE-----", + "payload": "tree e7a71825c01bc86dc7fe01eed981e16f743eb766\nparent 3a37795a9e8a696a86a761a7424dc6b35a973909\nauthor eps1lon 1608112215 +0100\ncommitter eps1lon 1608112215 +0100\n\nAdd tally of errors/warnings\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/91366be564aab76c4c8328eae7972844e4d244e6", + "html_url": "https://github.com/facebook/react/commit/91366be564aab76c4c8328eae7972844e4d244e6", + "comments_url": "https://api.github.com/repos/facebook/react/commits/91366be564aab76c4c8328eae7972844e4d244e6/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "3a37795a9e8a696a86a761a7424dc6b35a973909", + "url": "https://api.github.com/repos/facebook/react/commits/3a37795a9e8a696a86a761a7424dc6b35a973909", + "html_url": "https://github.com/facebook/react/commit/3a37795a9e8a696a86a761a7424dc6b35a973909" + } + ] + }, + { + "sha": "cc59c71ba644ede8acb1cf4112390f2c6ceef8e1", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmNjNTljNzFiYTY0NGVkZThhY2IxY2Y0MTEyMzkwZjJjNmNlZWY4ZTE=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T10:06:28Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T10:06:28Z" + }, + "message": "Remove nullish coalescing\n\nNot supported by jest config", + "tree": { + "sha": "978afbe5de988c6ea6a936d8528ee72c0c28dc30", + "url": "https://api.github.com/repos/facebook/react/git/trees/978afbe5de988c6ea6a936d8528ee72c0c28dc30" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/cc59c71ba644ede8acb1cf4112390f2c6ceef8e1", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/Z3CQACgkQWCcTbp05\ndTLs5xAApK2sfzQZX9c1L0Tp+mmh0QauT+1lyBbgzMghnSycSMxUeoG4qhUHWOnx\nnHE8OxelFbtsC5X+nk1cuMfb6cX64oa1tvoG5oM+tF3gALRSe2WVU8EDZyscbVrO\nLo9AQrTGJNMrjgi4T3SetFAQ6KFw+WaNgFzIxXZw8F2zWnQtV8XOVeH7e/heZPVQ\ndRZIIboh39bqYNBsJlcrA4wdLnG4yXYu9U9WkAP7cggnAJGoYSdcH2ItIiOKDzay\n0TDkL/3AdZR9m+wXaeL+kwAzq5RRaA+t3aU8y0SslGQW+YWGTUe3Q6zmQy9OQaps\nxJAmmCPWfOeYfQMc1P5MegtszHA2vb6T7I6eVnTAlCy2tHPfmSz3gIPqgo+JuPTB\n1vk2JFUaNEUYnBpbnRc6/UXmY8Zo14TfWDADM/zFB+K1cguh8acK9t+aYIMJNhcq\nGOdwXOIT937g4GcOWvCZvNhV6AqNru2yqt4lyG4s52gapeF0nPIbRiFpWtk91z+8\n66xTcULcAjauBXOUMB69b4xoM5mnMsHwIHerP3JRPOsaFuRUN3msQdR8hYtQPSas\nfzi3UOZS9X3XGzSEAyVo9N8jXoX9g8tjir6Zvn5hEaFrKGZ7CcdId6D+X5Eqp5bP\nkOn0CBF1842msrFPy0Qu/hZKo5Yy3wJPJserk4EPqwYQSfPuKW4=\n=GX/W\n-----END PGP SIGNATURE-----", + "payload": "tree 978afbe5de988c6ea6a936d8528ee72c0c28dc30\nparent 91366be564aab76c4c8328eae7972844e4d244e6\nauthor eps1lon 1608113188 +0100\ncommitter eps1lon 1608113188 +0100\n\nRemove nullish coalescing\n\nNot supported by jest config\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/cc59c71ba644ede8acb1cf4112390f2c6ceef8e1", + "html_url": "https://github.com/facebook/react/commit/cc59c71ba644ede8acb1cf4112390f2c6ceef8e1", + "comments_url": "https://api.github.com/repos/facebook/react/commits/cc59c71ba644ede8acb1cf4112390f2c6ceef8e1/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "91366be564aab76c4c8328eae7972844e4d244e6", + "url": "https://api.github.com/repos/facebook/react/commits/91366be564aab76c4c8328eae7972844e4d244e6", + "html_url": "https://github.com/facebook/react/commit/91366be564aab76c4c8328eae7972844e4d244e6" + } + ] + }, + { + "sha": "d164facbaa165423e5670fb208376aa510bf9df7", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmQxNjRmYWNiYWExNjU0MjNlNTY3MGZiMjA4Mzc2YWE1MTBiZjlkZjc=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T14:12:35Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T14:12:35Z" + }, + "message": "Cleaned up CSS colors and made some other small UI tweaks", + "tree": { + "sha": "51122f36200ca7ce01392f59f3e2f2d1b2c25364", + "url": "https://api.github.com/repos/facebook/react/git/trees/51122f36200ca7ce01392f59f3e2f2d1b2c25364" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/d164facbaa165423e5670fb208376aa510bf9df7", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/d164facbaa165423e5670fb208376aa510bf9df7", + "html_url": "https://github.com/facebook/react/commit/d164facbaa165423e5670fb208376aa510bf9df7", + "comments_url": "https://api.github.com/repos/facebook/react/commits/d164facbaa165423e5670fb208376aa510bf9df7/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "cc59c71ba644ede8acb1cf4112390f2c6ceef8e1", + "url": "https://api.github.com/repos/facebook/react/commits/cc59c71ba644ede8acb1cf4112390f2c6ceef8e1", + "html_url": "https://github.com/facebook/react/commit/cc59c71ba644ede8acb1cf4112390f2c6ceef8e1" + } + ] + }, + { + "sha": "860d0e7876c2d4824909aa95d7f86c1339c916ee", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjg2MGQwZTc4NzZjMmQ0ODI0OTA5YWE5NWQ3Zjg2YzEzMzljOTE2ZWU=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T14:43:39Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T14:43:39Z" + }, + "message": "Make more room in toolbar\n\nOnly show search controls when there is search text entered.\n\nDon't show error overlay in the owners view. (We also hide search controls in this view as well, to make more room for breadcrumbs", + "tree": { + "sha": "b66dcc52c867cf6448a721ea508334d574bad0fd", + "url": "https://api.github.com/repos/facebook/react/git/trees/b66dcc52c867cf6448a721ea508334d574bad0fd" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/860d0e7876c2d4824909aa95d7f86c1339c916ee", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/860d0e7876c2d4824909aa95d7f86c1339c916ee", + "html_url": "https://github.com/facebook/react/commit/860d0e7876c2d4824909aa95d7f86c1339c916ee", + "comments_url": "https://api.github.com/repos/facebook/react/commits/860d0e7876c2d4824909aa95d7f86c1339c916ee/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "d164facbaa165423e5670fb208376aa510bf9df7", + "url": "https://api.github.com/repos/facebook/react/commits/d164facbaa165423e5670fb208376aa510bf9df7", + "html_url": "https://github.com/facebook/react/commit/d164facbaa165423e5670fb208376aa510bf9df7" + } + ] + }, + { + "sha": "5cb19ac017b286cbd03a34c00bee728899027d07", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjVjYjE5YWMwMTdiMjg2Y2JkMDNhMzRjMDBiZWU3Mjg4OTkwMjdkMDc=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T15:23:32Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T15:23:32Z" + }, + "message": "Add new debug setting for showing inline warnings and errors\n\nRefactored console patching logic to account for this new setting.", + "tree": { + "sha": "30860f94c6092043678a13621d76cee2e08edfcc", + "url": "https://api.github.com/repos/facebook/react/git/trees/30860f94c6092043678a13621d76cee2e08edfcc" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/5cb19ac017b286cbd03a34c00bee728899027d07", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/5cb19ac017b286cbd03a34c00bee728899027d07", + "html_url": "https://github.com/facebook/react/commit/5cb19ac017b286cbd03a34c00bee728899027d07", + "comments_url": "https://api.github.com/repos/facebook/react/commits/5cb19ac017b286cbd03a34c00bee728899027d07/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "860d0e7876c2d4824909aa95d7f86c1339c916ee", + "url": "https://api.github.com/repos/facebook/react/commits/860d0e7876c2d4824909aa95d7f86c1339c916ee", + "html_url": "https://github.com/facebook/react/commit/860d0e7876c2d4824909aa95d7f86c1339c916ee" + } + ] + }, + { + "sha": "674e28779b9a204d4cdfe8b3c1d4dfeef78ee48d", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjY3NGUyODc3OWI5YTIwNGQ0Y2RmZThiM2MxZDRkZmVlZjc4ZWU0OGQ=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T15:39:55Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T15:39:55Z" + }, + "message": "Strip component stacks from errors/warnings before passing them to frontend", + "tree": { + "sha": "b35522412c8397ac7d2e61d42b33d6e9c73d21b7", + "url": "https://api.github.com/repos/facebook/react/git/trees/b35522412c8397ac7d2e61d42b33d6e9c73d21b7" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/674e28779b9a204d4cdfe8b3c1d4dfeef78ee48d", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/674e28779b9a204d4cdfe8b3c1d4dfeef78ee48d", + "html_url": "https://github.com/facebook/react/commit/674e28779b9a204d4cdfe8b3c1d4dfeef78ee48d", + "comments_url": "https://api.github.com/repos/facebook/react/commits/674e28779b9a204d4cdfe8b3c1d4dfeef78ee48d/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "5cb19ac017b286cbd03a34c00bee728899027d07", + "url": "https://api.github.com/repos/facebook/react/commits/5cb19ac017b286cbd03a34c00bee728899027d07", + "html_url": "https://github.com/facebook/react/commit/5cb19ac017b286cbd03a34c00bee728899027d07" + } + ] + }, + { + "sha": "0e0b8c7cd081d39cf4eb9138d7808349c95ad0a0", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjBlMGI4YzdjZDA4MWQzOWNmNGViOTEzOGQ3ODA4MzQ5Yzk1YWQwYTA=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T15:42:25Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T15:42:25Z" + }, + "message": "Fixed a spot I missed with new inline warnings setting", + "tree": { + "sha": "3195bd16377d77413330c4f7a714b266d936f4ef", + "url": "https://api.github.com/repos/facebook/react/git/trees/3195bd16377d77413330c4f7a714b266d936f4ef" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/0e0b8c7cd081d39cf4eb9138d7808349c95ad0a0", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/0e0b8c7cd081d39cf4eb9138d7808349c95ad0a0", + "html_url": "https://github.com/facebook/react/commit/0e0b8c7cd081d39cf4eb9138d7808349c95ad0a0", + "comments_url": "https://api.github.com/repos/facebook/react/commits/0e0b8c7cd081d39cf4eb9138d7808349c95ad0a0/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "674e28779b9a204d4cdfe8b3c1d4dfeef78ee48d", + "url": "https://api.github.com/repos/facebook/react/commits/674e28779b9a204d4cdfe8b3c1d4dfeef78ee48d", + "html_url": "https://github.com/facebook/react/commit/674e28779b9a204d4cdfe8b3c1d4dfeef78ee48d" + } + ] + }, + { + "sha": "5073d8193562a765b6c85fe225dfff7cc48a7d8a", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjUwNzNkODE5MzU2MmE3NjViNmM4NWZlMjI1ZGZmZjdjYzQ4YTdkOGE=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T16:26:26Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T16:26:26Z" + }, + "message": "De-dupe warnings and errors and show badge count for duplciate entries", + "tree": { + "sha": "6b806afca4cb96b814edf2393afc2da97742dc42", + "url": "https://api.github.com/repos/facebook/react/git/trees/6b806afca4cb96b814edf2393afc2da97742dc42" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/5073d8193562a765b6c85fe225dfff7cc48a7d8a", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/5073d8193562a765b6c85fe225dfff7cc48a7d8a", + "html_url": "https://github.com/facebook/react/commit/5073d8193562a765b6c85fe225dfff7cc48a7d8a", + "comments_url": "https://api.github.com/repos/facebook/react/commits/5073d8193562a765b6c85fe225dfff7cc48a7d8a/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "0e0b8c7cd081d39cf4eb9138d7808349c95ad0a0", + "url": "https://api.github.com/repos/facebook/react/commits/0e0b8c7cd081d39cf4eb9138d7808349c95ad0a0", + "html_url": "https://github.com/facebook/react/commit/0e0b8c7cd081d39cf4eb9138d7808349c95ad0a0" + } + ] + }, + { + "sha": "99de4ff77f62b5543db8536f71dd539b6598e626", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjk5ZGU0ZmY3N2Y2MmI1NTQzZGI4NTM2ZjcxZGQ1MzliNjU5OGU2MjY=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T16:32:39Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T16:32:39Z" + }, + "message": "Fixed dedupe badge text contrast", + "tree": { + "sha": "8f13c067a563ee7b8bdc8af8d1a2bf08b45c90d3", + "url": "https://api.github.com/repos/facebook/react/git/trees/8f13c067a563ee7b8bdc8af8d1a2bf08b45c90d3" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/99de4ff77f62b5543db8536f71dd539b6598e626", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/99de4ff77f62b5543db8536f71dd539b6598e626", + "html_url": "https://github.com/facebook/react/commit/99de4ff77f62b5543db8536f71dd539b6598e626", + "comments_url": "https://api.github.com/repos/facebook/react/commits/99de4ff77f62b5543db8536f71dd539b6598e626/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "5073d8193562a765b6c85fe225dfff7cc48a7d8a", + "url": "https://api.github.com/repos/facebook/react/commits/5073d8193562a765b6c85fe225dfff7cc48a7d8a", + "html_url": "https://github.com/facebook/react/commit/5073d8193562a765b6c85fe225dfff7cc48a7d8a" + } + ] + }, + { + "sha": "095c118e39fe7139bbf515efdbbd579b06eb83bd", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjA5NWMxMThlMzlmZTcxMzliYmY1MTVlZmRiYmQ1NzliMDZlYjgzYmQ=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T17:14:51Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T17:14:51Z" + }, + "message": "Oops I left a console log statement in", + "tree": { + "sha": "52b9db3bbc860712ed2a0963224c6ce528825edc", + "url": "https://api.github.com/repos/facebook/react/git/trees/52b9db3bbc860712ed2a0963224c6ce528825edc" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/095c118e39fe7139bbf515efdbbd579b06eb83bd", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/095c118e39fe7139bbf515efdbbd579b06eb83bd", + "html_url": "https://github.com/facebook/react/commit/095c118e39fe7139bbf515efdbbd579b06eb83bd", + "comments_url": "https://api.github.com/repos/facebook/react/commits/095c118e39fe7139bbf515efdbbd579b06eb83bd/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "99de4ff77f62b5543db8536f71dd539b6598e626", + "url": "https://api.github.com/repos/facebook/react/commits/99de4ff77f62b5543db8536f71dd539b6598e626", + "html_url": "https://github.com/facebook/react/commit/99de4ff77f62b5543db8536f71dd539b6598e626" + } + ] + }, + { + "sha": "e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmU4YjdkYzVmNTQ5ZjZjM2U2ZTQ0ZDQ1MDI4MWRjZDM1YWIzM2RmYWY=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T17:47:55Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T17:47:55Z" + }, + "message": "Minor UI tweaks", + "tree": { + "sha": "73826e1777deeccbf177a66b3888692b03ce3ef3", + "url": "https://api.github.com/repos/facebook/react/git/trees/73826e1777deeccbf177a66b3888692b03ce3ef3" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf", + "html_url": "https://github.com/facebook/react/commit/e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf", + "comments_url": "https://api.github.com/repos/facebook/react/commits/e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "095c118e39fe7139bbf515efdbbd579b06eb83bd", + "url": "https://api.github.com/repos/facebook/react/commits/095c118e39fe7139bbf515efdbbd579b06eb83bd", + "html_url": "https://github.com/facebook/react/commit/095c118e39fe7139bbf515efdbbd579b06eb83bd" + } + ] + }, + { + "sha": "3ab78dad37f03e83a9eb2024cf01175c31da9716", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjNhYjc4ZGFkMzdmMDNlODNhOWViMjAyNGNmMDExNzVjMzFkYTk3MTY=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T18:01:11Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T18:01:46Z" + }, + "message": "Clean up component stack remove in messages", + "tree": { + "sha": "48606957b02a829c62504708a48a5d749149a8e4", + "url": "https://api.github.com/repos/facebook/react/git/trees/48606957b02a829c62504708a48a5d749149a8e4" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/3ab78dad37f03e83a9eb2024cf01175c31da9716", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/aS4oACgkQWCcTbp05\ndTJKtA//duo+KKAuL2hkJOa10UZ0JA/XQxivjSsS3JZczcnTfEpmtZVxQitW3RrE\nzwkwU4QIcvjjfkwjyteheERKJkXBBnlC1E/iRDPDggSiOjJKCOD+C3ZBcltq/DCo\nROTTHs4/UrjRyev9nI66K3nvf5ukGuiMjZvKrgmTZLKdCZ/a3g7f6rkDMx9dDg4Z\n7yMR30srxEiG73EzIFEkYz+FkK8sHYggQRwT5r34ddxPnijevnuTkVh4gKA6E1yR\nrF3ljIBYF0Zncf/YqTOj2HRnDChds9fMmbBKUOY0GhBPYXXsmLmZ2XKZKfczFEvo\nfIqgvFZhw3bbzTZHJJpzCFUNEOph+xbDTKqNHyoTCg7LGAq9DrBmbUCJo0w7WOln\nhciHqqKo57lX0JOPB0erfT4WLIvng24kQjOxwc3N3BjUszdk27apj939yJi2AboC\nKsuIt7FO84oPQwJ+QvjezuHV4UTJHFASuEnKpQY6F60DOJW6fw54DhvX9GPcNSy7\nrgCLVHNhAk0ltXUS/skxI0mMZhcxZ+r7FKH+Dp3pxhzbXgriF1mOwbYPgKXgCuij\ni7eyHdPrQ5KqsO06IqS+no6nbqQHOngSvYf5U6PG0sLOWinIRXuqpnWPU1fqUMtj\nuJYR/Z+CfqXBibV8bLEuLa15046NXrU3GjM4cbZM/H9aBTKpL3M=\n=KZvZ\n-----END PGP SIGNATURE-----", + "payload": "tree 48606957b02a829c62504708a48a5d749149a8e4\nparent e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf\nauthor eps1lon 1608141671 +0100\ncommitter eps1lon 1608141706 +0100\n\nClean up component stack remove in messages\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/3ab78dad37f03e83a9eb2024cf01175c31da9716", + "html_url": "https://github.com/facebook/react/commit/3ab78dad37f03e83a9eb2024cf01175c31da9716", + "comments_url": "https://api.github.com/repos/facebook/react/commits/3ab78dad37f03e83a9eb2024cf01175c31da9716/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf", + "url": "https://api.github.com/repos/facebook/react/commits/e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf", + "html_url": "https://github.com/facebook/react/commit/e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf" + } + ] + }, + { + "sha": "15122d2a7e79a969b7f69166bcc181439bb5930c", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjE1MTIyZDJhN2U3OWE5NjliN2Y2OTE2NmJjYzE4MTQzOWJiNTkzMGM=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T18:10:40Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T18:10:40Z" + }, + "message": "Remove WIP artifacts", + "tree": { + "sha": "9fcef5af9b7a113223f4e8996632460e8d084158", + "url": "https://api.github.com/repos/facebook/react/git/trees/9fcef5af9b7a113223f4e8996632460e8d084158" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/15122d2a7e79a969b7f69166bcc181439bb5930c", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/aTaAACgkQWCcTbp05\ndTKcWRAAq76lymWDEUZv97/JJYqQ7j7mDKlYWKQzYSn082rdIZzg463S1p1hXPyH\nzdko9uni79rAw51xXN6oRuhkM60Cv3rBjg1FVRi+cdRPmAMAXesSnpbtc5DyW1Du\nRDZLPAZo8JJ3Xb8rLa+TyTfNjZgeddSjP67HATyWbGtEpMGANwwpi91unrv85b+4\nfDJUQaJMr+iL414kq061OHNcGTNEWZHUk/S8xcI+Z9hSlJytoT3HyAhIyRnUkTDP\noJBguwIHeOeftTAuilpRsCmaU8mRSAVYRjL4LqAfP25EZ7B1bQajm9LM9oHQJpvo\nBz7HAT+34OBX2ok+xzcp5Jl1s4D7LKgriq+xJ+kNFJipzKou2x+LOEPwql8ntDLn\nUw2NbDn3B0T4nlQ8hZNjIEDKCs0v2N2YIRySnfIfAwFKZvMwyShA7swZUbDKWGpx\n1usr2H41wz2qtJF3IXeaAPXPhgxH2toW9676St8yTBzxgw4TpBd5vmIKNh7yDsjS\nI/8CFBtefxekWi0+KVJOs7WFzauutLvjrzYgw4rZ1WWK44LcKPEoaXPY1Bw1Rm+l\nHUZ1COQO8KEGZsgwzfB8e4I9zy7sarArSRvhVAYJRq4joI3erKkEQMsVLq1OrDOv\nAdTOqUaegHFZHjGYkEEIo5OG/who7Vml2ETTg+5GLQoUAt6XcL0=\n=H78p\n-----END PGP SIGNATURE-----", + "payload": "tree 9fcef5af9b7a113223f4e8996632460e8d084158\nparent 3ab78dad37f03e83a9eb2024cf01175c31da9716\nauthor eps1lon 1608142240 +0100\ncommitter eps1lon 1608142240 +0100\n\nRemove WIP artifacts\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/15122d2a7e79a969b7f69166bcc181439bb5930c", + "html_url": "https://github.com/facebook/react/commit/15122d2a7e79a969b7f69166bcc181439bb5930c", + "comments_url": "https://api.github.com/repos/facebook/react/commits/15122d2a7e79a969b7f69166bcc181439bb5930c/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "3ab78dad37f03e83a9eb2024cf01175c31da9716", + "url": "https://api.github.com/repos/facebook/react/commits/3ab78dad37f03e83a9eb2024cf01175c31da9716", + "html_url": "https://github.com/facebook/react/commit/3ab78dad37f03e83a9eb2024cf01175c31da9716" + } + ] + }, + { + "sha": "26cecfa806e0ef8584db4985bfd145a71e643b66", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjI2Y2VjZmE4MDZlMGVmODU4NGRiNDk4NWJmZDE0NWE3MWU2NDNiNjY=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T18:28:54Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T18:28:54Z" + }, + "message": "Fixed bug when calculating total error/warning count", + "tree": { + "sha": "c2fdc0fddc2ad557508e7523b0c6ed18ed8da517", + "url": "https://api.github.com/repos/facebook/react/git/trees/c2fdc0fddc2ad557508e7523b0c6ed18ed8da517" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/26cecfa806e0ef8584db4985bfd145a71e643b66", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/26cecfa806e0ef8584db4985bfd145a71e643b66", + "html_url": "https://github.com/facebook/react/commit/26cecfa806e0ef8584db4985bfd145a71e643b66", + "comments_url": "https://api.github.com/repos/facebook/react/commits/26cecfa806e0ef8584db4985bfd145a71e643b66/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf", + "url": "https://api.github.com/repos/facebook/react/commits/e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf", + "html_url": "https://github.com/facebook/react/commit/e8b7dc5f549f6c3e6e44d450281dcd35ab33dfaf" + } + ] + }, + { + "sha": "1f1a161dafc6d53ec563508aea6a65b1f4538adc", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjFmMWExNjFkYWZjNmQ1M2VjNTYzNTA4YWVhNmE2NWIxZjQ1MzhhZGM=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T18:28:58Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T18:28:58Z" + }, + "message": "Merge branch 'devtools-show-warnings-in-tree' of github.com:eps1lon/react into devtools-show-warnings-in-tree", + "tree": { + "sha": "f8cf74e9a2674e3241efbb3e8c4dad20a816df77", + "url": "https://api.github.com/repos/facebook/react/git/trees/f8cf74e9a2674e3241efbb3e8c4dad20a816df77" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/1f1a161dafc6d53ec563508aea6a65b1f4538adc", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/1f1a161dafc6d53ec563508aea6a65b1f4538adc", + "html_url": "https://github.com/facebook/react/commit/1f1a161dafc6d53ec563508aea6a65b1f4538adc", + "comments_url": "https://api.github.com/repos/facebook/react/commits/1f1a161dafc6d53ec563508aea6a65b1f4538adc/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "26cecfa806e0ef8584db4985bfd145a71e643b66", + "url": "https://api.github.com/repos/facebook/react/commits/26cecfa806e0ef8584db4985bfd145a71e643b66", + "html_url": "https://github.com/facebook/react/commit/26cecfa806e0ef8584db4985bfd145a71e643b66" + }, + { + "sha": "15122d2a7e79a969b7f69166bcc181439bb5930c", + "url": "https://api.github.com/repos/facebook/react/commits/15122d2a7e79a969b7f69166bcc181439bb5930c", + "html_url": "https://github.com/facebook/react/commit/15122d2a7e79a969b7f69166bcc181439bb5930c" + } + ] + }, + { + "sha": "caf8678643bf6b91e8c8ae54f94de60b84c1a268", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmNhZjg2Nzg2NDNiZjZiOTFlOGM4YWU1NGY5NGRlNjBiODRjMWEyNjg=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T18:38:52Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T18:38:52Z" + }, + "message": "Use empty string instead of \"fixing\" the format string", + "tree": { + "sha": "c2506818c918b9aebb91724f5835f0a72b4caf5f", + "url": "https://api.github.com/repos/facebook/react/git/trees/c2506818c918b9aebb91724f5835f0a72b4caf5f" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/caf8678643bf6b91e8c8ae54f94de60b84c1a268", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/aVDwACgkQWCcTbp05\ndTIXdBAAhQi/hbQwEEvm/nGKCtglUC6Pdg6lxN6ndhn0O57qW7Og8z0l51tHeBQV\n2fLuxLg88BY4Nh4Gyb9s6jjjnyDsmoQnY5brwWwKR1ytCrpK5WWNmyqsmAH7atTM\nh/IrYUBFDGPp2hmGCgIpUs7Ko50X1TUxFsdcosV1bRXAFNapyjvNzqoxF4PKa3J4\ny0JlaTvPCiSFSUtIjo1s2U61BLZbfEhs6wwYUj2KJYm0mqI6Naq4c14GnFoVriNK\nNznO0rUviRiirkVmLhnbkLPNcSSZQdf0A8trxENva6H+LnwdErouzzZwsRJuqYcW\nXKb3Z7YTtXczdzY6HIWP6WKd/oShWWAc8GDF3Uto3fS2p0MxoCncc59ZnNyNUAeh\nWyldGBlKKmX6gdmFS790RPAhlYdXWyhR1jYG0kxJM5KVXtM3p3tHZQ9SvJIkSaHH\nGE/kSIfyVjZr7mxeTInHQpHgHKA66BT+ZZ65SjL247SHsZQtqaKdOCPqKTlYca7f\nJ9E09rr3MzA/+8Zx49PVSA1Gp3iFAD4VKnUQB7r0JjzdxrSnqP6HSAWEScf8l6mO\ntcxv4FUvbciWxfdfjH+fZMYYMa9uYck8yi3m/FHxensaRofwm+xNoGAAdCqOdwN7\nclgVPybNMAYsos1S2bsjY8eNA9m1XSArQ8fVImhjcduPplWc7Pc=\n=A2Jo\n-----END PGP SIGNATURE-----", + "payload": "tree c2506818c918b9aebb91724f5835f0a72b4caf5f\nparent 1f1a161dafc6d53ec563508aea6a65b1f4538adc\nauthor eps1lon 1608143932 +0100\ncommitter eps1lon 1608143932 +0100\n\nUse empty string instead of \"fixing\" the format string\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/caf8678643bf6b91e8c8ae54f94de60b84c1a268", + "html_url": "https://github.com/facebook/react/commit/caf8678643bf6b91e8c8ae54f94de60b84c1a268", + "comments_url": "https://api.github.com/repos/facebook/react/commits/caf8678643bf6b91e8c8ae54f94de60b84c1a268/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "1f1a161dafc6d53ec563508aea6a65b1f4538adc", + "url": "https://api.github.com/repos/facebook/react/commits/1f1a161dafc6d53ec563508aea6a65b1f4538adc", + "html_url": "https://github.com/facebook/react/commit/1f1a161dafc6d53ec563508aea6a65b1f4538adc" + } + ] + }, + { + "sha": "a4f005992b6bcddf67539cd04eafe0d1c50effc9", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmE0ZjAwNTk5MmI2YmNkZGY2NzUzOWNkMDRlYWZlMGQxYzUwZWZmYzk=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T19:03:17Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T19:03:17Z" + }, + "message": "Fix test harness to avoid double logging\n\nComponent stack generation relies on intentionally triggering common sources of errors when shallow-rendering a component. Our inline error test harness didn't trip these paths for most components, and so it appeared to double log most of its warnings/errors. This commit fixes that.", + "tree": { + "sha": "a1b02708f238017d0268f6fc562b60b1f85e6bb4", + "url": "https://api.github.com/repos/facebook/react/git/trees/a1b02708f238017d0268f6fc562b60b1f85e6bb4" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/a4f005992b6bcddf67539cd04eafe0d1c50effc9", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/a4f005992b6bcddf67539cd04eafe0d1c50effc9", + "html_url": "https://github.com/facebook/react/commit/a4f005992b6bcddf67539cd04eafe0d1c50effc9", + "comments_url": "https://api.github.com/repos/facebook/react/commits/a4f005992b6bcddf67539cd04eafe0d1c50effc9/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "caf8678643bf6b91e8c8ae54f94de60b84c1a268", + "url": "https://api.github.com/repos/facebook/react/commits/caf8678643bf6b91e8c8ae54f94de60b84c1a268", + "html_url": "https://github.com/facebook/react/commit/caf8678643bf6b91e8c8ae54f94de60b84c1a268" + } + ] + }, + { + "sha": "5719f31d19f21e72c8f72d91549b6cdcb2163970", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjU3MTlmMzFkMTlmMjFlNzJjOGY3MmQ5MTU0OWI2Y2RjYjIxNjM5NzA=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T19:07:23Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T19:07:23Z" + }, + "message": "Added a few more test cases to the inline error test harness", + "tree": { + "sha": "81748d53e3a447093f441669a743680acdad79c8", + "url": "https://api.github.com/repos/facebook/react/git/trees/81748d53e3a447093f441669a743680acdad79c8" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/5719f31d19f21e72c8f72d91549b6cdcb2163970", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/5719f31d19f21e72c8f72d91549b6cdcb2163970", + "html_url": "https://github.com/facebook/react/commit/5719f31d19f21e72c8f72d91549b6cdcb2163970", + "comments_url": "https://api.github.com/repos/facebook/react/commits/5719f31d19f21e72c8f72d91549b6cdcb2163970/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "a4f005992b6bcddf67539cd04eafe0d1c50effc9", + "url": "https://api.github.com/repos/facebook/react/commits/a4f005992b6bcddf67539cd04eafe0d1c50effc9", + "html_url": "https://github.com/facebook/react/commit/a4f005992b6bcddf67539cd04eafe0d1c50effc9" + } + ] + }, + { + "sha": "92ebd817278e1024094c02995a4f7a586777ef4f", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjkyZWJkODE3Mjc4ZTEwMjQwOTRjMDI5OTVhNGY3YTU4Njc3N2VmNGY=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T19:18:21Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T19:18:21Z" + }, + "message": "Show full message on click", + "tree": { + "sha": "cb815069fc425bdc6a2d16a6c8b01ec57b8ab067", + "url": "https://api.github.com/repos/facebook/react/git/trees/cb815069fc425bdc6a2d16a6c8b01ec57b8ab067" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/92ebd817278e1024094c02995a4f7a586777ef4f", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/aXX4ACgkQWCcTbp05\ndTIJ3g//YSC0lrvm4OssnHIgDIIYxhuq4dF9Z8itJhpZLYYPia+fN1q8vXRUhpqu\n4F3OnVztlQrQngdWBkke3AinsHGjWLB1E9VP8Zhlr04QvgU48hl8CDUtMrrh2DEm\nSmj3j/qaxdLBY+7Ii7RkVex68oVYSbQOkV3mx/OVOFPto7tNXgsD7m9WCFjeLCUd\nEy7dQXjMl3Wgt8Da+UQEqnqPllv5uX/oios9CXXqhZ9nTAjzpNKKHnPCzRYgVFj+\nwSSaO/0HRzOjv50xUYtTMcgshmGSBnhDvtN9Stuisi575EHU8boNsu7//VQ1Kbqm\nia4AaUFHE/cKgnAUTLdWEnxNhaLxhUQCCErITZeaoDLtdIgPV+7BntjoqJcJ/uws\nABXNZtjIKEj3hZLqdFNprdT5cJ+0+vJaMhOYIh3acu8uPfN+1ozy2BqDlK2n1pbP\nWMhT5EqeBR/CGZusydLCFuISg9Ez0IwGlZvm2dMXix3LRnUissCKUoGTRcGiNlRZ\noMhVYP0EzvHpb9NtfR8Pd2sXi7gRl6rmNo3ewfEOKq8Q3XPbqyBXqrD7MqHAQZzT\n2D1mXh6ycPhVAE30eubJyz0WBDln8kOg8Ubu1itjIX9ZQKEudLkluZF2DRLKkpkG\nRMy3B8PcNQCc0gEu5x5C+sA5T3SwSPaV1ztMjxLSzsMoPhqZJkA=\n=r+la\n-----END PGP SIGNATURE-----", + "payload": "tree cb815069fc425bdc6a2d16a6c8b01ec57b8ab067\nparent 5719f31d19f21e72c8f72d91549b6cdcb2163970\nauthor eps1lon 1608146301 +0100\ncommitter eps1lon 1608146301 +0100\n\nShow full message on click\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/92ebd817278e1024094c02995a4f7a586777ef4f", + "html_url": "https://github.com/facebook/react/commit/92ebd817278e1024094c02995a4f7a586777ef4f", + "comments_url": "https://api.github.com/repos/facebook/react/commits/92ebd817278e1024094c02995a4f7a586777ef4f/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "5719f31d19f21e72c8f72d91549b6cdcb2163970", + "url": "https://api.github.com/repos/facebook/react/commits/5719f31d19f21e72c8f72d91549b6cdcb2163970", + "html_url": "https://github.com/facebook/react/commit/5719f31d19f21e72c8f72d91549b6cdcb2163970" + } + ] + }, + { + "sha": "70099e5638be567f7ef1d0d0edfb165f0c5ef9b5", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjcwMDk5ZTU2MzhiZTU2N2Y3ZWYxZDBkMGVkZmIxNjVmMGM1ZWY5YjU=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T20:03:59Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T20:03:59Z" + }, + "message": "Revert 92ebd81", + "tree": { + "sha": "6bb1a109c054ae9aba211c743ea9db018177038c", + "url": "https://api.github.com/repos/facebook/react/git/trees/6bb1a109c054ae9aba211c743ea9db018177038c" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/70099e5638be567f7ef1d0d0edfb165f0c5ef9b5", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/70099e5638be567f7ef1d0d0edfb165f0c5ef9b5", + "html_url": "https://github.com/facebook/react/commit/70099e5638be567f7ef1d0d0edfb165f0c5ef9b5", + "comments_url": "https://api.github.com/repos/facebook/react/commits/70099e5638be567f7ef1d0d0edfb165f0c5ef9b5/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "92ebd817278e1024094c02995a4f7a586777ef4f", + "url": "https://api.github.com/repos/facebook/react/commits/92ebd817278e1024094c02995a4f7a586777ef4f", + "html_url": "https://github.com/facebook/react/commit/92ebd817278e1024094c02995a4f7a586777ef4f" + } + ] + }, + { + "sha": "1b6e29277ead380dc90bb560c339680c201dcab6", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjFiNmUyOTI3N2VhZDM4MGRjOTBiYjU2MGMzMzk2ODBjMjAxZGNhYjY=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T20:12:41Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T20:12:41Z" + }, + "message": "Show full error/warning text as tooltip on hover", + "tree": { + "sha": "f57387359f5556303c12460bb1d3c0474382bfa8", + "url": "https://api.github.com/repos/facebook/react/git/trees/f57387359f5556303c12460bb1d3c0474382bfa8" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/1b6e29277ead380dc90bb560c339680c201dcab6", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/1b6e29277ead380dc90bb560c339680c201dcab6", + "html_url": "https://github.com/facebook/react/commit/1b6e29277ead380dc90bb560c339680c201dcab6", + "comments_url": "https://api.github.com/repos/facebook/react/commits/1b6e29277ead380dc90bb560c339680c201dcab6/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "70099e5638be567f7ef1d0d0edfb165f0c5ef9b5", + "url": "https://api.github.com/repos/facebook/react/commits/70099e5638be567f7ef1d0d0edfb165f0c5ef9b5", + "html_url": "https://github.com/facebook/react/commit/70099e5638be567f7ef1d0d0edfb165f0c5ef9b5" + } + ] + } +] \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/clients/pull_request_commits_page3.json b/src/test/resources/com/spotify/github/v3/clients/pull_request_commits_page3.json new file mode 100644 index 00000000..979ae360 --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/clients/pull_request_commits_page3.json @@ -0,0 +1,1902 @@ +[ + { + "sha": "61bf6a36a5bfd9b297ce8057f449a5f99ff6a1ee", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjYxYmY2YTM2YTViZmQ5YjI5N2NlODA1N2Y0NDlhNWY5OWZmNmExZWU=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T20:15:45Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T20:15:45Z" + }, + "message": "inline errors and warnings are not implemented in legacy devtools", + "tree": { + "sha": "9c694f3fceb045ebadd915845d8fa3ff9b40b87d", + "url": "https://api.github.com/repos/facebook/react/git/trees/9c694f3fceb045ebadd915845d8fa3ff9b40b87d" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/61bf6a36a5bfd9b297ce8057f449a5f99ff6a1ee", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/aavEACgkQWCcTbp05\ndTJ5UQ/+KofyRcLItGUo23HKV4cagrKhHyKHQUtal4sfEAwPp1flh6Oh+dbw2dGB\nT2kUQyh0cWAQ1zcS/1e+ci3Mojm1hURI0A6x0FJJhsnBFLGEqz7pTGMyl0bCtFYE\nM8xysQSx6kmHFhZXEfXTreH8u0YBxLBMWJuQVU2+M/6Rs057LdWpth4dGiAcJfl1\nllPv4AdzVZ073rqFmVlgNvBgrUxuoSaI9KXVsim4X3Qdr5CP2MFfl34RdEAtW5hy\nxVX9O/dJjnHgyb38mbkwpM6mSeXuFsuY3biZeeLahqt/E3v+GOrAUlXUicEmbPKR\n8uFkyCzw/mY7qc7Zzw4RvIG4ncOsxiNqT55jhZn8MNARqpdCodENEYWQ2Bc1jWsE\nFsH2FYb0DdZN+asXUDx465bXlMDe+Tmfi5l8Kanh4oMUQ5Y8ASrg50tSprpZoAil\n/BBVuwHIVQwkE5LatG9DRWRbHDAneOEZ1Fy5UYvbQnyc+QTuPM8UbB4kmCQsLBVN\n7hMzx+FnpLaBmf1q+XH3p0FhHytaciZZCUhpdnlhw+xauQELFoFX3En/XeDMegTR\nIYHjOPWeh5wbiFLfrxe+RnATll+Ft4h4ecBfxhmHcE2dDnQCZvIWYJ9o58uRWzEb\ngIL+EdCKMnXfRDUIvbR202tPUPsivAXBKaaNxQn7VBi4V7PWp88=\n=ZzOy\n-----END PGP SIGNATURE-----", + "payload": "tree 9c694f3fceb045ebadd915845d8fa3ff9b40b87d\nparent 1b6e29277ead380dc90bb560c339680c201dcab6\nauthor eps1lon 1608149745 +0100\ncommitter eps1lon 1608149745 +0100\n\ninline errors and warnings are not implemented in legacy devtools\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/61bf6a36a5bfd9b297ce8057f449a5f99ff6a1ee", + "html_url": "https://github.com/facebook/react/commit/61bf6a36a5bfd9b297ce8057f449a5f99ff6a1ee", + "comments_url": "https://api.github.com/repos/facebook/react/commits/61bf6a36a5bfd9b297ce8057f449a5f99ff6a1ee/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "1b6e29277ead380dc90bb560c339680c201dcab6", + "url": "https://api.github.com/repos/facebook/react/commits/1b6e29277ead380dc90bb560c339680c201dcab6", + "html_url": "https://github.com/facebook/react/commit/1b6e29277ead380dc90bb560c339680c201dcab6" + } + ] + }, + { + "sha": "46cea44df06b30c4e44db1be886cffa9150ce298", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjQ2Y2VhNDRkZjA2YjMwYzRlNDRkYjFiZTg4NmNmZmE5MTUwY2UyOTg=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T20:29:46Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T20:29:46Z" + }, + "message": "Added missing key error test", + "tree": { + "sha": "711b0c3d1d86ef81ed8c9d9b9842c5d6a36dabdc", + "url": "https://api.github.com/repos/facebook/react/git/trees/711b0c3d1d86ef81ed8c9d9b9842c5d6a36dabdc" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/46cea44df06b30c4e44db1be886cffa9150ce298", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/46cea44df06b30c4e44db1be886cffa9150ce298", + "html_url": "https://github.com/facebook/react/commit/46cea44df06b30c4e44db1be886cffa9150ce298", + "comments_url": "https://api.github.com/repos/facebook/react/commits/46cea44df06b30c4e44db1be886cffa9150ce298/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "61bf6a36a5bfd9b297ce8057f449a5f99ff6a1ee", + "url": "https://api.github.com/repos/facebook/react/commits/61bf6a36a5bfd9b297ce8057f449a5f99ff6a1ee", + "html_url": "https://github.com/facebook/react/commit/61bf6a36a5bfd9b297ce8057f449a5f99ff6a1ee" + } + ] + }, + { + "sha": "8b5c8d9c354b7dc1a31cdcac8bf997a2d2c77f80", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjhiNWM4ZDljMzU0YjdkYzFhMzFjZGNhYzhiZjk5N2EyZDJjNzdmODA=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T20:53:09Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T20:53:09Z" + }, + "message": "Move batching to backend/console", + "tree": { + "sha": "792e668f200e1b711837638b03cd28c97a62c31d", + "url": "https://api.github.com/repos/facebook/react/git/trees/792e668f200e1b711837638b03cd28c97a62c31d" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/8b5c8d9c354b7dc1a31cdcac8bf997a2d2c77f80", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/ac7UACgkQWCcTbp05\ndTK4dg//eASfA66HR2GhpPTULA31taWaEk1DmiM+kKp7XKpdeCqOrMebcC6F8rkl\n8rWv17LsO66gQ2V0OeGdMUyQTXPiMj22yNPTZGNQ7BCHCkEVFUsUF3RjO3k6OTqJ\n87AKBwRsw/VUTBwo6ME24R/9u0q3q+BBEXoS1cOkN8hl6x331hYJAmyr5irSu3ql\nRyBnwbamtuqdiIMZD+ljou6L86c8YmTuk0pNIZjEF7DP3z4N452zPbyjwzVgQhN1\noTFc+BvWitUJ1YAHdelVsobmUDHshDME7wy9ZZioX2kD0psDFU+1jx6K1ZUMDs2h\nX1J+LW2sY5zjs5Zgsn6FwCM3C2O/k5RciGsS9Hj2dtej2ttlttAEs7+5kCyqhFX7\nnDSoKUAiaMlKO0YgFm0Q8RIhdOcOSuR0nQe8218jk1GmS2KmhiY21Uq6ZhqFIwrR\nk2LZpXH5NIZxbNGFFOgTE3SG6LUM/tUkvwYoeJgwrPIT9I0u7Lchnly572+dm8pB\naIeCI2K0YnoQlkbSYg2NXuYSFnuGa+sh2J5+dxsIcz2C7OmvLaPqN/eVcdyHzods\nfB9RaeaVb7imZEmM6a94pNKBO5yTOFDgUug1H3i9WvhcctSR/05+5JQNtEbfXnhg\n0p2aOVKUAH1c6mANPvMUcaP+TKSHY+4wLbfD+7NRLLeU4ges4c8=\n=OEqg\n-----END PGP SIGNATURE-----", + "payload": "tree 792e668f200e1b711837638b03cd28c97a62c31d\nparent 46cea44df06b30c4e44db1be886cffa9150ce298\nauthor eps1lon 1608151989 +0100\ncommitter eps1lon 1608151989 +0100\n\nMove batching to backend/console\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/8b5c8d9c354b7dc1a31cdcac8bf997a2d2c77f80", + "html_url": "https://github.com/facebook/react/commit/8b5c8d9c354b7dc1a31cdcac8bf997a2d2c77f80", + "comments_url": "https://api.github.com/repos/facebook/react/commits/8b5c8d9c354b7dc1a31cdcac8bf997a2d2c77f80/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "46cea44df06b30c4e44db1be886cffa9150ce298", + "url": "https://api.github.com/repos/facebook/react/commits/46cea44df06b30c4e44db1be886cffa9150ce298", + "html_url": "https://github.com/facebook/react/commit/46cea44df06b30c4e44db1be886cffa9150ce298" + } + ] + }, + { + "sha": "0146bc33b572a8caa2537c68907a0536964a5a9c", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjAxNDZiYzMzYjU3MmE4Y2FhMjUzN2M2ODkwN2EwNTM2OTY0YTVhOWM=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T21:04:45Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-16T21:04:45Z" + }, + "message": "move filter into forEach", + "tree": { + "sha": "edef577b2b6806681914010f72f86a4d3a88f269", + "url": "https://api.github.com/repos/facebook/react/git/trees/edef577b2b6806681914010f72f86a4d3a88f269" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/0146bc33b572a8caa2537c68907a0536964a5a9c", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/adm0ACgkQWCcTbp05\ndTLzsA/9EpDR5cXG/4TeASS+jHImAZi3T93c4obZNnRzBPBr3vkG41pzJmzc7/x0\nB2FNNcDd+SpjSVYzq4hkKFbvRpPvLwSB7rjRg/fFhAWSI56tNFn+3CBRnmrlj5ee\nwGInqpLX9sxPkVDeIRRA6/DOAAwwoplnqHukgKNz3SNZ7EgHsmRmClhTFnoLItgf\nnLihUiASfVPYz1ZqtUuuJgYkiBa6vqeO4CjeOYq7Y179mvs4Rl3E1JXJp19oljvJ\nITr59NJbAEMr1NmovpK+wPX+RKw/3E/MSylZlZfwjK4GEyz0iLnAnB4Jr/vkW9be\noTRa4WiGeDeReNeSrnT7rxMvH6nkBm6F6Yci10lpwadyP85WdqiocK3YK9Vxr1QF\nIatyEAbkKZ0va9pNlPCc6eZ9jFFv7Eb8d6VgDeK4LMRiHwTdoadfehRiNHkuwo3X\nQrvo1eVCDn1bQfWy2arDRPKiD7q9dqBizPWJBXLAiDea1PGn6/ASVMS4ozn4WVUx\ncetUtAxJelonv5XzlSQ8pcPntp4JV7RsJcLhU9CjHg53dD5yoABcHB4XMxelr2oi\nbowd1oNCUkrxsHFXcuyGaajQqFVwxd700ye3/pWY6GuUthM/0sN41pinYf5tEvxD\nkbA0uK7QVmXECD6ou2maF4h0knvwftGBAyB/TLnzHZHRd5mNOvw=\n=r3g8\n-----END PGP SIGNATURE-----", + "payload": "tree edef577b2b6806681914010f72f86a4d3a88f269\nparent 8b5c8d9c354b7dc1a31cdcac8bf997a2d2c77f80\nauthor eps1lon 1608152685 +0100\ncommitter eps1lon 1608152685 +0100\n\nmove filter into forEach\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/0146bc33b572a8caa2537c68907a0536964a5a9c", + "html_url": "https://github.com/facebook/react/commit/0146bc33b572a8caa2537c68907a0536964a5a9c", + "comments_url": "https://api.github.com/repos/facebook/react/commits/0146bc33b572a8caa2537c68907a0536964a5a9c/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "8b5c8d9c354b7dc1a31cdcac8bf997a2d2c77f80", + "url": "https://api.github.com/repos/facebook/react/commits/8b5c8d9c354b7dc1a31cdcac8bf997a2d2c77f80", + "html_url": "https://github.com/facebook/react/commit/8b5c8d9c354b7dc1a31cdcac8bf997a2d2c77f80" + } + ] + }, + { + "sha": "04ffb01ae43218916a1ed60991793250f7da3fcb", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjA0ZmZiMDFhZTQzMjE4OTE2YTFlZDYwOTkxNzkzMjUwZjdkYTNmY2I=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T21:26:48Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-16T21:26:48Z" + }, + "message": "Added some basic tests for inline errors/warnings", + "tree": { + "sha": "2e883a823bfc718df921aba3ca5f411cd04afe9f", + "url": "https://api.github.com/repos/facebook/react/git/trees/2e883a823bfc718df921aba3ca5f411cd04afe9f" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/04ffb01ae43218916a1ed60991793250f7da3fcb", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/04ffb01ae43218916a1ed60991793250f7da3fcb", + "html_url": "https://github.com/facebook/react/commit/04ffb01ae43218916a1ed60991793250f7da3fcb", + "comments_url": "https://api.github.com/repos/facebook/react/commits/04ffb01ae43218916a1ed60991793250f7da3fcb/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "0146bc33b572a8caa2537c68907a0536964a5a9c", + "url": "https://api.github.com/repos/facebook/react/commits/0146bc33b572a8caa2537c68907a0536964a5a9c", + "html_url": "https://github.com/facebook/react/commit/0146bc33b572a8caa2537c68907a0536964a5a9c" + } + ] + }, + { + "sha": "9380545c50e3b14a0e3a898c1767beb17f11f652", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjkzODA1NDVjNTBlM2IxNGEwZTNhODk4YzE3NjdiZWIxN2YxMWY2NTI=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T14:53:41Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T14:53:41Z" + }, + "message": "Add tests for the store", + "tree": { + "sha": "e42ae8d43865b38b2570a9fc2692fa30781dc3f6", + "url": "https://api.github.com/repos/facebook/react/git/trees/e42ae8d43865b38b2570a9fc2692fa30781dc3f6" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/9380545c50e3b14a0e3a898c1767beb17f11f652", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/bcPUACgkQWCcTbp05\ndTJIbw//WoNUVNVYzxq+JO1sksVz1Xhc/vEzkTRowuGXCLukm92ahy8oB79O/K7f\nqvHCB734JueaIhcefFaUVMTr7VEEz78uJEiqZF0MWNx9Op/1uhVXZ/TRiJjlAE5f\ncmKdX8ssGTP8+zhAgB5lZ5jeci02qGFvb2pC0PUygF24QXXC8gPzqXR7MRoNhtjD\n6KbjaOXx/0sgLsk8VmfsML7Smmz9lG6YqB7+3mM5z1+8CF2ksXlGmYlDZ7e3vROM\nY6Rw7/hPJHOrU9HCSKOYazB8jRo6PiiIzvp1MJZLnqXgyoruhm9cfg8SrkdcRA0n\nI+9nObhrZz5m/u+eChBT6xIgcLKD6TE+DioLrpSNHwSr6h4d5s+6nJa9uG11CqGs\nZo8XGwTyfqvVBv0MGgvD/mxsybETZOOvCTfuYpaB6LiLGIuircHD9Y39be+nsCrm\nGEVjxuRvXjlBenDPTlCAWYrJGmwDda8xW+C4DTLjS5bdfVyEMfSaMtdKZok6mDT3\nFWNAyKQyMSvaLCiKldpCMC0d+XcbVj0MF9VaUdRi1TGImqiV/mN8LTZFnPTrVXMP\n9pYduGfxBWGTuoj9fEqOxJh36bZfxzmsNQaARsVbIkzrqxgI5xhiGJrDpNyX3kPi\nvdulPh1JQws0oE0bOnnlxRiPyiNpwhd5B/SpgJQBZdyyO4HTHSk=\n=p3P9\n-----END PGP SIGNATURE-----", + "payload": "tree e42ae8d43865b38b2570a9fc2692fa30781dc3f6\nparent 04ffb01ae43218916a1ed60991793250f7da3fcb\nauthor eps1lon 1608216821 +0100\ncommitter eps1lon 1608216821 +0100\n\nAdd tests for the store\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/9380545c50e3b14a0e3a898c1767beb17f11f652", + "html_url": "https://github.com/facebook/react/commit/9380545c50e3b14a0e3a898c1767beb17f11f652", + "comments_url": "https://api.github.com/repos/facebook/react/commits/9380545c50e3b14a0e3a898c1767beb17f11f652/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "04ffb01ae43218916a1ed60991793250f7da3fcb", + "url": "https://api.github.com/repos/facebook/react/commits/04ffb01ae43218916a1ed60991793250f7da3fcb", + "html_url": "https://github.com/facebook/react/commit/04ffb01ae43218916a1ed60991793250f7da3fcb" + } + ] + }, + { + "sha": "8ff2c7b098eda20f73c05e8e997a61c258231864", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjhmZjJjN2IwOThlZGEyMGY3M2MwNWU4ZTk5N2E2MWMyNTgyMzE4NjQ=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T16:07:54Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T16:07:54Z" + }, + "message": "Update snapshot due to previous typo fix", + "tree": { + "sha": "a914fb41ebfae2a51e7608d503fe33984e4be2d2", + "url": "https://api.github.com/repos/facebook/react/git/trees/a914fb41ebfae2a51e7608d503fe33984e4be2d2" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/8ff2c7b098eda20f73c05e8e997a61c258231864", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/bgloACgkQWCcTbp05\ndTIELRAAprOLIDb3QLEeos9ctxu4sITTciv+JVm3RYEi5BYmvkc/WbGzBilU9FhW\nfbVirYIkqq+VEi0NhJ1oHFwLf9+tvosZuXqLXV6doakUVtOg5glmatidiD8h61mS\nScxfuU3WdH1YyKo/bGexdA0ZGv/mq4lbqQhBxSkFeE9zSuZt/nC97k1d01ZrHQg0\nkObtSBHlu0vKTX0Vr0gAN3Wumfw5mOoEmbkx4HR+qHV8YaYsXOEou1RXSQJKCQJo\nbdl27y0sJEvMo2qzEDwE9XjMp8UUcgcDuMNe3irjryMA9rFbolNoo+mQ3POyvmL5\nFSxsV9t/taKjXpcw1+1e5cb1LkKblXnS8/tOiIXnq8HIh+19CFLPV+hl2ASrp9CR\nWdVl5RDIxCK/2rw7RRPXvabHKMohnOlCRmylxv5RGRiXPpCRVQ4sViJfWpaQjDj6\nXAuf7897awWlnJSnIMs0exepPX/SSds5hyg/eCMyKnfGzcsOG0c4ktkYJjbRIgyU\nTk7HOKvJYziJdCJYTva5Aoga9yqXqxgVcXQ14G9CeVXXYwmm1s+pePpNoESomWeV\nkETg42uOKxZ/I5GSV7kVq2AVQ+eNwEvlos/dUYgnvwSwmL/FwDcwsytT914HqT6L\nG8vW/a/cJaDx/bRDEbTsSoz2ZtXs0mKDmzIOzKYO2mWyhd/9Nm0=\n=ZApv\n-----END PGP SIGNATURE-----", + "payload": "tree a914fb41ebfae2a51e7608d503fe33984e4be2d2\nparent 9380545c50e3b14a0e3a898c1767beb17f11f652\nauthor eps1lon 1608221274 +0100\ncommitter eps1lon 1608221274 +0100\n\nUpdate snapshot due to previous typo fix\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/8ff2c7b098eda20f73c05e8e997a61c258231864", + "html_url": "https://github.com/facebook/react/commit/8ff2c7b098eda20f73c05e8e997a61c258231864", + "comments_url": "https://api.github.com/repos/facebook/react/commits/8ff2c7b098eda20f73c05e8e997a61c258231864/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "9380545c50e3b14a0e3a898c1767beb17f11f652", + "url": "https://api.github.com/repos/facebook/react/commits/9380545c50e3b14a0e3a898c1767beb17f11f652", + "html_url": "https://github.com/facebook/react/commit/9380545c50e3b14a0e3a898c1767beb17f11f652" + } + ] + }, + { + "sha": "5824f48de70c944eaf0c1c82f5baf3ca770f86e4", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjU4MjRmNDhkZTcwYzk0NGVhZjBjMWM4MmY1YmFmM2NhNzcwZjg2ZTQ=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T16:09:40Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T16:09:40Z" + }, + "message": "Remove outdated snapshot", + "tree": { + "sha": "2b08941996c079067be8348c06621b137e79b312", + "url": "https://api.github.com/repos/facebook/react/git/trees/2b08941996c079067be8348c06621b137e79b312" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/5824f48de70c944eaf0c1c82f5baf3ca770f86e4", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/5824f48de70c944eaf0c1c82f5baf3ca770f86e4", + "html_url": "https://github.com/facebook/react/commit/5824f48de70c944eaf0c1c82f5baf3ca770f86e4", + "comments_url": "https://api.github.com/repos/facebook/react/commits/5824f48de70c944eaf0c1c82f5baf3ca770f86e4/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "8ff2c7b098eda20f73c05e8e997a61c258231864", + "url": "https://api.github.com/repos/facebook/react/commits/8ff2c7b098eda20f73c05e8e997a61c258231864", + "html_url": "https://github.com/facebook/react/commit/8ff2c7b098eda20f73c05e8e997a61c258231864" + } + ] + }, + { + "sha": "8fc62494adfa8cc20eb94478eb64508b452adb69", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjhmYzYyNDk0YWRmYThjYzIwZWI5NDQ3OGViNjQ1MDhiNDUyYWRiNjk=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T16:29:01Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T16:29:01Z" + }, + "message": "Refactored error/warning message queueing and bundling", + "tree": { + "sha": "c7177d9d798a5ef60bf3479504f751d84c114d42", + "url": "https://api.github.com/repos/facebook/react/git/trees/c7177d9d798a5ef60bf3479504f751d84c114d42" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/8fc62494adfa8cc20eb94478eb64508b452adb69", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/8fc62494adfa8cc20eb94478eb64508b452adb69", + "html_url": "https://github.com/facebook/react/commit/8fc62494adfa8cc20eb94478eb64508b452adb69", + "comments_url": "https://api.github.com/repos/facebook/react/commits/8fc62494adfa8cc20eb94478eb64508b452adb69/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "5824f48de70c944eaf0c1c82f5baf3ca770f86e4", + "url": "https://api.github.com/repos/facebook/react/commits/5824f48de70c944eaf0c1c82f5baf3ca770f86e4", + "html_url": "https://github.com/facebook/react/commit/5824f48de70c944eaf0c1c82f5baf3ca770f86e4" + } + ] + }, + { + "sha": "f0ceff6f856e846c18d9267de8294752b5c8f4f8", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmYwY2VmZjZmODU2ZTg0NmMxOGQ5MjY3ZGU4Mjk0NzUyYjVjOGY0Zjg=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T16:36:53Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T16:36:53Z" + }, + "message": "Fixed Store tests by updating to inline snapshots", + "tree": { + "sha": "e2dc5f4d8a81d5f388593635b6362865da1e87f4", + "url": "https://api.github.com/repos/facebook/react/git/trees/e2dc5f4d8a81d5f388593635b6362865da1e87f4" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/f0ceff6f856e846c18d9267de8294752b5c8f4f8", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/f0ceff6f856e846c18d9267de8294752b5c8f4f8", + "html_url": "https://github.com/facebook/react/commit/f0ceff6f856e846c18d9267de8294752b5c8f4f8", + "comments_url": "https://api.github.com/repos/facebook/react/commits/f0ceff6f856e846c18d9267de8294752b5c8f4f8/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "8fc62494adfa8cc20eb94478eb64508b452adb69", + "url": "https://api.github.com/repos/facebook/react/commits/8fc62494adfa8cc20eb94478eb64508b452adb69", + "html_url": "https://github.com/facebook/react/commit/8fc62494adfa8cc20eb94478eb64508b452adb69" + } + ] + }, + { + "sha": "1c1874c4bed1718f32b951a52bc669fe6d992d14", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjFjMTg3NGM0YmVkMTcxOGYzMmI5NTFhNTJiYzY2OWZlNmQ5OTJkMTQ=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T17:04:55Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T17:04:55Z" + }, + "message": "Prevent siliencing of unexpected console calls in inspectedElementContext-test", + "tree": { + "sha": "93c091bf94cbdb16f98ecbdd93c710b035937c72", + "url": "https://api.github.com/repos/facebook/react/git/trees/93c091bf94cbdb16f98ecbdd93c710b035937c72" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/1c1874c4bed1718f32b951a52bc669fe6d992d14", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/bj7cACgkQWCcTbp05\ndTJY1g/+PSzg4b++rN4nz+8mqopGFgC9tEC7ot9me7CidrOFbFyjzuO3uBCWyPnw\ntD2pi/2irF++6KNiST96TSGjX3MC/U/24wUiiijkpgEZHESPWBO+/COHE1tJX4RD\nDtBd1c7mFYHnpCNrtLDC3n+64k0fdrOZQQkGYZKPOzif2qeYQ5V63nQOjQEeuQec\nQLQkkvrn3t0TuB7yNtcBwGrC117mekoW6P/qeHn/DDTwwhUX4kLwjlqItbmxsu4Y\n/mAVHtFuMqoLNQBNwWq33vtohFO8RK22q5XO+ByrNp9uJ71xTeQYH5YJhLnCAwmY\nCx0jJbqMoy6g0qOqoN+J1ASnurmLD0a6jVdp13awHSBljUs7085D/qosQc0rTMVS\nZhHRm1zmyyJHtqrn22ijOTfC+H2PUY5rzb4S287XhAEHZNqAWQuKenA80yBDJCC6\n0+uXmMJm4/JHiFMMv8jWHur9GwuiGfXuC8las2HcoJ9uHFWq7Ytb/BJnHF9F4OSu\nQOvdchW+28zRYjfEoLQpKx0sCt6Dq6c67puOeQMZtghtwdaVD/zWYuNBN5hJXX7K\n1Fywb56vwytkgUkA7JQqbAvIjrJiafMxquLU5ck0Vk89uSyrieG4MlHSEbwl9VII\nmeXiC6LK+ReMEKpCEB2GNazY3wa9aNh12L+Jj8eKSc1VszWO1Jo=\n=jXp6\n-----END PGP SIGNATURE-----", + "payload": "tree 93c091bf94cbdb16f98ecbdd93c710b035937c72\nparent f0ceff6f856e846c18d9267de8294752b5c8f4f8\nauthor eps1lon 1608224695 +0100\ncommitter eps1lon 1608224695 +0100\n\nPrevent siliencing of unexpected console calls in inspectedElementContext-test\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/1c1874c4bed1718f32b951a52bc669fe6d992d14", + "html_url": "https://github.com/facebook/react/commit/1c1874c4bed1718f32b951a52bc669fe6d992d14", + "comments_url": "https://api.github.com/repos/facebook/react/commits/1c1874c4bed1718f32b951a52bc669fe6d992d14/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "f0ceff6f856e846c18d9267de8294752b5c8f4f8", + "url": "https://api.github.com/repos/facebook/react/commits/f0ceff6f856e846c18d9267de8294752b5c8f4f8", + "html_url": "https://github.com/facebook/react/commit/f0ceff6f856e846c18d9267de8294752b5c8f4f8" + } + ] + }, + { + "sha": "ef149c9e0dc7aa95c256849dbe99d5d29d248335", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmVmMTQ5YzllMGRjN2FhOTVjMjU2ODQ5ZGJlOTlkNWQyOWQyNDgzMzU=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T17:39:36Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T17:39:36Z" + }, + "message": "Actually use generic param", + "tree": { + "sha": "034a89d997ea5a2788d7154e712cd32c4b95dab2", + "url": "https://api.github.com/repos/facebook/react/git/trees/034a89d997ea5a2788d7154e712cd32c4b95dab2" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/ef149c9e0dc7aa95c256849dbe99d5d29d248335", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/bl9gACgkQWCcTbp05\ndTJ1Tw//VMzPMHDn7ogH68I2MQ5x5JvVz9FJDh4HeAKDUjjHZ3u0i1IB0JDEJsyO\nm/RGptpyiNhurWa/wbaTWzZ7XXTbs6Xx90t3j6ciIOBEvDdBb/KQ+LbY3EoozwsJ\nHIn4yWE+Q4laANamsZIasoQblNXjP5QAmU+5sA4asWAf2EXYpo8McqdoKCnsyT2K\neJVnTzqkXIJLUWvgsUh12xdsrpfQ5cxh0kMj6erifGMM9f2VvRXMdZrbdIqqe3X4\nRyqTeoDvfJXYW7Zk5udp6C+5ZhL1Vd5vbrApm3V3dUYWV9t8Iic79iF8waUUBh8o\nUFUCWS3aQHrIdZ06wSSd6O2o6tpCJqzQh5lyvsIs3ZCbya7as+e40OCVb5PquzO0\nl3V2+UewIqazhXBNXBqKLo4jyFAn3w41DtFMvGPJW+3pTtrLU7qcbQ7B05LYUUbE\nBojV10OjB3XbY4VR+S9Rqm8q8VST5ZaTN5ent0SXLDbPMW97tHv+GUqPRrDUFfci\nJ3DAvv1dk65fEmo0y2HIQTsYBr8q/yBGZnzSSaT4CCmhXWz7gqT/z59IoQpS5fFx\nAjM7jhDvqCDj66THykuov0XimauW2LNDPShGQGgBeR5VnESxd5uT13lG/63OwR4X\ng4qefC7S8KlfRKjqHOBz6Uw+aEl6UCsnw0MY0rk1eLupFX6SFw8=\n=EWhf\n-----END PGP SIGNATURE-----", + "payload": "tree 034a89d997ea5a2788d7154e712cd32c4b95dab2\nparent 1c1874c4bed1718f32b951a52bc669fe6d992d14\nauthor eps1lon 1608226776 +0100\ncommitter eps1lon 1608226776 +0100\n\nActually use generic param\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/ef149c9e0dc7aa95c256849dbe99d5d29d248335", + "html_url": "https://github.com/facebook/react/commit/ef149c9e0dc7aa95c256849dbe99d5d29d248335", + "comments_url": "https://api.github.com/repos/facebook/react/commits/ef149c9e0dc7aa95c256849dbe99d5d29d248335/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "1c1874c4bed1718f32b951a52bc669fe6d992d14", + "url": "https://api.github.com/repos/facebook/react/commits/1c1874c4bed1718f32b951a52bc669fe6d992d14", + "html_url": "https://github.com/facebook/react/commit/1c1874c4bed1718f32b951a52bc669fe6d992d14" + } + ] + }, + { + "sha": "5c892ac2db1d1174731e0a07704be7e7562a9496", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjVjODkyYWMyZGIxZDExNzQ3MzFlMGEwNzcwNGJlN2U3NTYyYTk0OTY=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T17:46:52Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T17:46:52Z" + }, + "message": "Use inline snapshots", + "tree": { + "sha": "574b2c9db0a3267e3ba4acc1da6db9b6f0e5332a", + "url": "https://api.github.com/repos/facebook/react/git/trees/574b2c9db0a3267e3ba4acc1da6db9b6f0e5332a" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/5c892ac2db1d1174731e0a07704be7e7562a9496", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/bmYwACgkQWCcTbp05\ndTLeGRAAked7WzXdQnJce34Qb4v3PWT/2N9f3EqkANvlg6zYhwr03V/ebQw2Wl1M\nILpTCfYxmj7oowSuarPFq/a24Jlo3yx9If++y8dvFCq6jGZ0wAoWpm8014xQX6ku\nqfV+pLwvYlSQo2r7yXzdDIGUCA3HmSCaHPaupyEjDkK2S14puKtp/dmk5qe0kbxA\n6xivxiwP1HaIEZ7Hlu49w1FTXlfezDILXiN1xYB2WXT+fQqLmmil155t0WrxK5jP\nS+ultpiYEDbtF1ZjKWup0jzxmL6Oxf3RkzBzm83x9juc2QNRaXUB+Lc2jj7hSBOq\nF7gA6RquNzOgagxCTo12U3onrs89F0P+R7CEMFdnJS7ZZLftPdzj4rqXxEQ67Myv\ntImNfIxs6TtDb7zo/iVADrVZXrJgYqnsfqhdnJDvPxgrxcEUwgB5lE9xUgwex8At\nGm50PuGhurzf1L/Lkdc7qZpkKtIOH5jzOfqWLuiu8QE4zc/Cd6JS1wXnkbKNYfrU\n0n002dz3PBhBGnawNb8zZ7Nmbc9JWR9pnODkWioU6m3RSJWYvyYGUlIZQOa4D07E\nI9tALyDCqLUZ0iGSsqnJnWojsQbWNScrL5RUtGdvg/BlprrZnCAEJZJwJ4gxVi56\nYcR4t9WtXKEOuGJIN4jOA81MzCUc5UWdbKCrdC0VtFx3hmciboo=\n=4n2E\n-----END PGP SIGNATURE-----", + "payload": "tree 574b2c9db0a3267e3ba4acc1da6db9b6f0e5332a\nparent ef149c9e0dc7aa95c256849dbe99d5d29d248335\nauthor eps1lon 1608227212 +0100\ncommitter eps1lon 1608227212 +0100\n\nUse inline snapshots\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/5c892ac2db1d1174731e0a07704be7e7562a9496", + "html_url": "https://github.com/facebook/react/commit/5c892ac2db1d1174731e0a07704be7e7562a9496", + "comments_url": "https://api.github.com/repos/facebook/react/commits/5c892ac2db1d1174731e0a07704be7e7562a9496/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "ef149c9e0dc7aa95c256849dbe99d5d29d248335", + "url": "https://api.github.com/repos/facebook/react/commits/ef149c9e0dc7aa95c256849dbe99d5d29d248335", + "html_url": "https://github.com/facebook/react/commit/ef149c9e0dc7aa95c256849dbe99d5d29d248335" + } + ] + }, + { + "sha": "8953cdc6503b8a73ce5f27a5522865ac48c6c465", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjg5NTNjZGM2NTAzYjhhNzNjZTVmMjdhNTUyMjg2NWFjNDhjNmM0NjU=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T18:46:14Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T18:56:11Z" + }, + "message": "Add tests for clearing errors and warnings", + "tree": { + "sha": "d6cfd9c239da749ea68557f404234104e09eda01", + "url": "https://api.github.com/repos/facebook/react/git/trees/d6cfd9c239da749ea68557f404234104e09eda01" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/8953cdc6503b8a73ce5f27a5522865ac48c6c465", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/bqcsACgkQWCcTbp05\ndTLDUA//bDq3xwMKoFaIE1z0toaAveWlTQniac9qdEVCd4Vw3m1ZurlSnWAgC1i2\nZtgbSrGC+vw8kJeh+Ya7ma09U0WKilySO8AeKaaoHVe8OJOw8+r/VCzfRigMazbf\nYmqt6gwVaiJ2YIn1tzsjAABwRQrnzwVKwzzsOarnQMjfJLZOYeYwc6myJdRef/AW\nsXVE7Z8SVlfcExQm8CYS98VCH9p7Z0zHAaBKVYw2BoNehxU6oGRPXSNIw58rGS5H\nQGuPuDRa6GKyDIM7N0uXaCWiTwzIDq2yvh4UxeAHipM0h61vPoOkV5xV7K+1KHdN\nBHRvbe7CZ8+gOqIm+MS9LPcq/18ltlfFI9Oskm6kS5xyyb0GDd84ZegMVGyC1DMG\n0whkKKnke3JmSUPRKbhinheST/YN7qLrsvZtlCfLtvyNwVXpPMwo+M3aiDHhHVvj\nkapol/9xn/mvG2sTxyOu1srHDF4Ra3vowiIU0yR/0dJhPjIqjYQGXcqpNxhZBDT4\n8QvrSKup7UII4LvsgXdnsVHLFxhnsRCeXSlUMF2SuhdakXEt43EFB3xHhEMD4tYb\nssF7IUmvX85PxCOTMZXbq0RTGFpCRIeVAdjU92E5ywlkHg0gCIZuKz6WWq3VDs4h\nDeGoaeW8lmqCJ7VyRYNLd69+mQWe2bzp3YTs2Z//tBHJYbPOjoE=\n=RhyO\n-----END PGP SIGNATURE-----", + "payload": "tree d6cfd9c239da749ea68557f404234104e09eda01\nparent 5c892ac2db1d1174731e0a07704be7e7562a9496\nauthor eps1lon 1608230774 +0100\ncommitter eps1lon 1608231371 +0100\n\nAdd tests for clearing errors and warnings\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/8953cdc6503b8a73ce5f27a5522865ac48c6c465", + "html_url": "https://github.com/facebook/react/commit/8953cdc6503b8a73ce5f27a5522865ac48c6c465", + "comments_url": "https://api.github.com/repos/facebook/react/commits/8953cdc6503b8a73ce5f27a5522865ac48c6c465/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "5c892ac2db1d1174731e0a07704be7e7562a9496", + "url": "https://api.github.com/repos/facebook/react/commits/5c892ac2db1d1174731e0a07704be7e7562a9496", + "html_url": "https://github.com/facebook/react/commit/5c892ac2db1d1174731e0a07704be7e7562a9496" + } + ] + }, + { + "sha": "268a25b169aa612447622a8c5ba5afedce6e584e", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjI2OGEyNWIxNjlhYTYxMjQ0NzYyMmE4YzViYTVhZmVkY2U2ZTU4NGU=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T18:58:13Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T18:58:13Z" + }, + "message": "Run the minimal amount of timer necessary", + "tree": { + "sha": "aeb3df251ff62f2260906fbdb1efd73492bf8483", + "url": "https://api.github.com/repos/facebook/react/git/trees/aeb3df251ff62f2260906fbdb1efd73492bf8483" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/268a25b169aa612447622a8c5ba5afedce6e584e", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/bqkUACgkQWCcTbp05\ndTIHQBAAqWs4RVLuLKUrwNeRrsYKzKm4jzQTuLtJcuJFmkqci1L1y2sHHiwdE6k4\nMs3+1NWLUJElPgAVGOEqiV1GdtS4ku1yntJAeyRu/E5FpGV7ZnNDJdsy//vC1CA3\n860a4DFU5M4vHB6ycYcIOW2GipLYJ43VzGoID9ErxnHPhoy7Y2SqQckZZTkerKFj\nK4OKkHHxhB5yXVt7dY/lTua+uEWaDK6MeWLAdVnAHpXJS5j8fk8nR37bQeGe5ZJf\ntThYihTsz5mQ6HdJ47yy4zGUzGdw6rvlqhzRAwzb9ld8OQEvFBKY/iZOWYZNHZF0\nklXTFpQBFBn9k1+U6h0lT9TuGH2jnI5u2wN92Q03G5uOM6Em0k9dbslk+td7h8wY\nv1RqPvaNXowEHtoMqk5zsieVcTvUFALyAsZ7o362Vrf1o1WrdDRJy344qtGy/y4x\npxVG59AYd0IeB8sttHxf5Choi90C4K4bOGJSRphd8G3e5UBC7i3S9q3KpJ2/tI45\n3b8zFI5LuJrpeu2zVj2BSfhGC2shMfJYmX/dYzZ9gUqL26Fw/aDxsnjIO/LWob94\nYEQp8kUFbqF27UIgxleLJ1arVNnRv4+TFVhWn+q/7Hq0vzbrM8zbMpsq357VXj1X\n/LaY3oCinx6lZRk5k4t6qTA4RFIHUKx+lNkuj4IPDO/3pQxnR8I=\n=MK7j\n-----END PGP SIGNATURE-----", + "payload": "tree aeb3df251ff62f2260906fbdb1efd73492bf8483\nparent 8953cdc6503b8a73ce5f27a5522865ac48c6c465\nauthor eps1lon 1608231493 +0100\ncommitter eps1lon 1608231493 +0100\n\nRun the minimal amount of timer necessary\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/268a25b169aa612447622a8c5ba5afedce6e584e", + "html_url": "https://github.com/facebook/react/commit/268a25b169aa612447622a8c5ba5afedce6e584e", + "comments_url": "https://api.github.com/repos/facebook/react/commits/268a25b169aa612447622a8c5ba5afedce6e584e/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "8953cdc6503b8a73ce5f27a5522865ac48c6c465", + "url": "https://api.github.com/repos/facebook/react/commits/8953cdc6503b8a73ce5f27a5522865ac48c6c465", + "html_url": "https://github.com/facebook/react/commit/8953cdc6503b8a73ce5f27a5522865ac48c6c465" + } + ] + }, + { + "sha": "6e167a3f300352c21aa696258c1b8759c1a1a082", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjZlMTY3YTNmMzAwMzUyYzIxYWE2OTYyNThjMWI4NzU5YzFhMWEwODI=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T19:07:50Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-17T19:07:50Z" + }, + "message": "Revert \"Run the minimal amount of timer necessary\"\n\nThis reverts commit 268a25b169aa612447622a8c5ba5afedce6e584e.", + "tree": { + "sha": "d6cfd9c239da749ea68557f404234104e09eda01", + "url": "https://api.github.com/repos/facebook/react/git/trees/d6cfd9c239da749ea68557f404234104e09eda01" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/6e167a3f300352c21aa696258c1b8759c1a1a082", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/brIgACgkQWCcTbp05\ndTIpKBAAnQHFjeV52CTgQI/CjPUe7IIfYgWt20EL9gkcQmVG0gAJCVVybAwUwtOT\naseGsLauomKfm30s6besa5JyGCPuL/fV0vIj6m2dAPHuKPkxjs0843Ir73Kw90eV\n+4FtYGF0y/dhEXbbNC2/T/ScCTBbta2I8mzVTyZHJtkg37fS58vJaUOeLwNxjGGs\n3haEbgtxP9tpld7gjsdAN5z60DG9owuyDBZOdGet9GQMW9TBQjDryojqx0XU2BOf\nE5AGObTu8UVnriEOOJL/b7q+R6VTbysBMT4TC37/CnwnnBAKBXD18tT4rbuk9d8z\n5ScMDesAsVS2a+Ig9NcklB26TQ2oZBvrlN6duU1/b7kfHy0J9HlCMFJqgz3g5zX1\n8i3QjfHHI9vhmAkBpNVt2PVPjmLQr/N/gsZTnGoPNV7wJGXdTbJqwens30bCmyU5\nvjQB2dVJBDS/rSls/H5K6UCEOJ9fuvfLVNS7uP0ivE4hd/9P4RO4gEv+lc5kVpqH\neu1IF8YITkXEZAru2ibjbBzLAjlFj8bkcvcLR1D8XUBgreg1R7Gc+djozBAGpJI4\nxytp5bP7Ll2oUUur3K/AQUSci190YIyo+xCcFmyRofcczfy9GaLZ+Gjbpu81LTUi\nvepCWBzdeyiVq+d2Uz38pSdt+/csoxRCQJ/hZBlUyBoSiX84U54=\n=yV+S\n-----END PGP SIGNATURE-----", + "payload": "tree d6cfd9c239da749ea68557f404234104e09eda01\nparent 268a25b169aa612447622a8c5ba5afedce6e584e\nauthor eps1lon 1608232070 +0100\ncommitter eps1lon 1608232070 +0100\n\nRevert \"Run the minimal amount of timer necessary\"\n\nThis reverts commit 268a25b169aa612447622a8c5ba5afedce6e584e.\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/6e167a3f300352c21aa696258c1b8759c1a1a082", + "html_url": "https://github.com/facebook/react/commit/6e167a3f300352c21aa696258c1b8759c1a1a082", + "comments_url": "https://api.github.com/repos/facebook/react/commits/6e167a3f300352c21aa696258c1b8759c1a1a082/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "268a25b169aa612447622a8c5ba5afedce6e584e", + "url": "https://api.github.com/repos/facebook/react/commits/268a25b169aa612447622a8c5ba5afedce6e584e", + "html_url": "https://github.com/facebook/react/commit/268a25b169aa612447622a8c5ba5afedce6e584e" + } + ] + }, + { + "sha": "69410ac9edb9b13cead6dbb46f9a0ea0b2c6cd0d", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjY5NDEwYWM5ZWRiOWIxM2NlYWQ2ZGJiNDZmOWEwZWEwYjJjNmNkMGQ=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T21:35:10Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T21:35:10Z" + }, + "message": "Added tests (and bug fix) for select next/prev error", + "tree": { + "sha": "26180e46fa934907bf58d77563ef679d598cc6f9", + "url": "https://api.github.com/repos/facebook/react/git/trees/26180e46fa934907bf58d77563ef679d598cc6f9" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/69410ac9edb9b13cead6dbb46f9a0ea0b2c6cd0d", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/69410ac9edb9b13cead6dbb46f9a0ea0b2c6cd0d", + "html_url": "https://github.com/facebook/react/commit/69410ac9edb9b13cead6dbb46f9a0ea0b2c6cd0d", + "comments_url": "https://api.github.com/repos/facebook/react/commits/69410ac9edb9b13cead6dbb46f9a0ea0b2c6cd0d/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "6e167a3f300352c21aa696258c1b8759c1a1a082", + "url": "https://api.github.com/repos/facebook/react/commits/6e167a3f300352c21aa696258c1b8759c1a1a082", + "html_url": "https://github.com/facebook/react/commit/6e167a3f300352c21aa696258c1b8759c1a1a082" + } + ] + }, + { + "sha": "6feb404501cae6cbc827d13229e0b02d81884e35", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjZmZWI0MDQ1MDFjYWU2Y2JjODI3ZDEzMjI5ZTBiMDJkODE4ODRlMzU=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T23:16:41Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T23:16:41Z" + }, + "message": "Fixed an error (but left a TODO for a better future fix)", + "tree": { + "sha": "8fec934be9a7e4c0851b7c912b71186d62fbcf9a", + "url": "https://api.github.com/repos/facebook/react/git/trees/8fec934be9a7e4c0851b7c912b71186d62fbcf9a" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/6feb404501cae6cbc827d13229e0b02d81884e35", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/6feb404501cae6cbc827d13229e0b02d81884e35", + "html_url": "https://github.com/facebook/react/commit/6feb404501cae6cbc827d13229e0b02d81884e35", + "comments_url": "https://api.github.com/repos/facebook/react/commits/6feb404501cae6cbc827d13229e0b02d81884e35/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "69410ac9edb9b13cead6dbb46f9a0ea0b2c6cd0d", + "url": "https://api.github.com/repos/facebook/react/commits/69410ac9edb9b13cead6dbb46f9a0ea0b2c6cd0d", + "html_url": "https://github.com/facebook/react/commit/69410ac9edb9b13cead6dbb46f9a0ea0b2c6cd0d" + } + ] + }, + { + "sha": "da0aad2cbf39db3fbf2d6bda303ac33f5b7f92bd", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmRhMGFhZDJjYmYzOWRiM2ZiZjJkNmJkYTMwM2FjMzNmNWI3ZjkyYmQ=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T23:28:36Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-17T23:28:36Z" + }, + "message": "Added two (failing) tests that we should fix", + "tree": { + "sha": "b7324c78c7814e6d20c3fbccfe7dcf44dc7ad59a", + "url": "https://api.github.com/repos/facebook/react/git/trees/b7324c78c7814e6d20c3fbccfe7dcf44dc7ad59a" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/da0aad2cbf39db3fbf2d6bda303ac33f5b7f92bd", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/da0aad2cbf39db3fbf2d6bda303ac33f5b7f92bd", + "html_url": "https://github.com/facebook/react/commit/da0aad2cbf39db3fbf2d6bda303ac33f5b7f92bd", + "comments_url": "https://api.github.com/repos/facebook/react/commits/da0aad2cbf39db3fbf2d6bda303ac33f5b7f92bd/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "6feb404501cae6cbc827d13229e0b02d81884e35", + "url": "https://api.github.com/repos/facebook/react/commits/6feb404501cae6cbc827d13229e0b02d81884e35", + "html_url": "https://github.com/facebook/react/commit/6feb404501cae6cbc827d13229e0b02d81884e35" + } + ] + }, + { + "sha": "35b16ce7d9e14ff5544a4c61293eae1c0ff510eb", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjM1YjE2Y2U3ZDllMTRmZjU1NDRhNGM2MTI5M2VhZTFjMGZmNTEwZWI=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-18T10:04:09Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-18T10:04:09Z" + }, + "message": "select(Prev|Next)Error -> select(Prev|Next)ErrorOrWarning\n\nMaybe we should've called it \"Issues\" instead but now that we've written it so often we might as well keep it?!\nOr just avoid the bikeshedding altogether...", + "tree": { + "sha": "fb266c3ad9eafaa1a83e14154c7db9bbdde4d6ef", + "url": "https://api.github.com/repos/facebook/react/git/trees/fb266c3ad9eafaa1a83e14154c7db9bbdde4d6ef" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/35b16ce7d9e14ff5544a4c61293eae1c0ff510eb", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/cfpkACgkQWCcTbp05\ndTIZCBAAkoxAgP5gw2nGRxL8ow4BKwgL3/Gn8NM3UGoLoe3jhP7ceWTrPPejO8Q+\n4gRW+teqz5kfHNYlAnmOUSue3aKKXX2v3dF5mG4KiwFYNpOkPlE/6fFTLbyvqxVv\nFdu6x1Vm8dZceqc5y8a2jcn+ajCjf/YEZE5LYmpigl7Cjlrk6tF3BlsY2s8NiZ3/\nPRgH3aOOsEHWIkmLlMriTI8m6caN1EcC7PBi3DDiTzfDIz4FK8ZTxIWqyS0vEAIP\n/NZ+rysV/xj+dW8zvx4h9RBNyX/y8AYnFJIJfkxOoiBDTW5U73tqtkqz8Gau/6ue\nHrSBMlRyR1Fby5dnjI1+2pmKp8PjrcN2LOO9VNRKrS9BWWCTDWyshnOfPm1shtMC\nMSxRTY2kP1f9fkNVI7a15FqU88r7ZbUezY82e7n+3hM3+7WZCTESAnWMLddr8Ung\nCAr/oI7C3VsHx8ImoI1VmqaijBj8xW4+b+zTB1UoyrtV1L5MSr/K4lah01Oiw3id\n6pYXOVw1PAPOO1UMiRHtVYKbq4SnvCLKORMmtU1COZjMJkxF5obWWJh/6Pt7NOQL\nooZ939mug+lr/7tXvAT7xYEkBHwxgsfiYdApok4yp2ryfQ7HgRAlNu/2gxol73tf\nNLXam3otNwsjrB86O0Ib9dfmBLhCqBRA9toJ5CZN/zsXsjC1+JU=\n=uyxh\n-----END PGP SIGNATURE-----", + "payload": "tree fb266c3ad9eafaa1a83e14154c7db9bbdde4d6ef\nparent da0aad2cbf39db3fbf2d6bda303ac33f5b7f92bd\nauthor eps1lon 1608285849 +0100\ncommitter eps1lon 1608285849 +0100\n\nselect(Prev|Next)Error -> select(Prev|Next)ErrorOrWarning\n\nMaybe we should've called it \"Issues\" instead but now that we've written it so often we might as well keep it?!\nOr just avoid the bikeshedding altogether...\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/35b16ce7d9e14ff5544a4c61293eae1c0ff510eb", + "html_url": "https://github.com/facebook/react/commit/35b16ce7d9e14ff5544a4c61293eae1c0ff510eb", + "comments_url": "https://api.github.com/repos/facebook/react/commits/35b16ce7d9e14ff5544a4c61293eae1c0ff510eb/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "da0aad2cbf39db3fbf2d6bda303ac33f5b7f92bd", + "url": "https://api.github.com/repos/facebook/react/commits/da0aad2cbf39db3fbf2d6bda303ac33f5b7f92bd", + "html_url": "https://github.com/facebook/react/commit/da0aad2cbf39db3fbf2d6bda303ac33f5b7f92bd" + } + ] + }, + { + "sha": "af1c54ed8f5a528028eac4512f5a33f143a5c5e1", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmFmMWM1NGVkOGY1YTUyODAyOGVhYzQ1MTJmNWEzM2YxNDNhNWM1ZTE=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-18T10:55:40Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-18T10:55:40Z" + }, + "message": "Serialize errors and warnings in snapshots", + "tree": { + "sha": "869af1b4246b10b959639fbed569293342feff22", + "url": "https://api.github.com/repos/facebook/react/git/trees/869af1b4246b10b959639fbed569293342feff22" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/af1c54ed8f5a528028eac4512f5a33f143a5c5e1", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/ciqwACgkQWCcTbp05\ndTIdiA//TYIhuuUpXOhHA6HBHBaSnaBGOJZYixs694+yNenUn/NhE3qITcltp1aN\nF5Z2qAFNq0G4F2iXAj+fJGHsw801BmYmTSUNbnOelh1u5GhAvM6vud6duZ4hQjZ3\nHA3rDbIJkswiLEhaY2DSOj8S4sWBSX/Jl49XqUdWeuqrR4wxIJjpYJ3QiFcslOq4\nh8YG1C+A9QtVKr1pAAxWRrK6BOCe1PMSQUPm+WCSpUUh4f9mdCzwaEBjd5BMLJWc\nMZ12gVm9T3SMstnMGu4eoESNQbrtR1a+t382J1s+7AEphX0QizOhhmKaWD+NK3zT\ne5vqfAhtf5S3OdNwjkwd3zgNpPOxveCTpAQlATL7AOK8Jpn1E9RCrMpfTMvfixSg\nWp3ODz7i731mIdW3j1Ywvz3K/7J1B60qVfVhdD7oudb4OYOfE2UpJqvl/3ngeY5z\nSLHIBAqL1+4pp+PMdVcU2AhDUOX1KER5L5NG/0FW2mqcbz/P1XK7CptS/dbblKq/\nDIrsdISRTh9HXzV+ozOwSLHNyVKe1PteaaJLMl/fMmnxH8bzsTRRFDNdX1JqfGYl\nSA0ZVXS0YnynskNQOIbG8v1BatfJaItc15sBVvU4WwYfULzVmdyac3N9PZxWv9zL\nrT1JgSiCIzs1RlKaAPdw9WYmH+jripXUv8qym5yM0jWmBFFwtJE=\n=dL8u\n-----END PGP SIGNATURE-----", + "payload": "tree 869af1b4246b10b959639fbed569293342feff22\nparent 35b16ce7d9e14ff5544a4c61293eae1c0ff510eb\nauthor eps1lon 1608288940 +0100\ncommitter eps1lon 1608288940 +0100\n\nSerialize errors and warnings in snapshots\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/af1c54ed8f5a528028eac4512f5a33f143a5c5e1", + "html_url": "https://github.com/facebook/react/commit/af1c54ed8f5a528028eac4512f5a33f143a5c5e1", + "comments_url": "https://api.github.com/repos/facebook/react/commits/af1c54ed8f5a528028eac4512f5a33f143a5c5e1/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "35b16ce7d9e14ff5544a4c61293eae1c0ff510eb", + "url": "https://api.github.com/repos/facebook/react/commits/35b16ce7d9e14ff5544a4c61293eae1c0ff510eb", + "html_url": "https://github.com/facebook/react/commit/35b16ce7d9e14ff5544a4c61293eae1c0ff510eb" + } + ] + }, + { + "sha": "a0a8e060f0a7681abbad222fdd2a0c6e9943185d", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmEwYThlMDYwZjBhNzY4MWFiYmFkMjIyZmRkMmEwYzZlOTk0MzE4NWQ=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-18T11:22:58Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-18T11:22:58Z" + }, + "message": "Use statefulStore serializer in \"inline error/warning\" tests", + "tree": { + "sha": "c3b2f6cab2521fe8be6ceb84ca6e614fc86addad", + "url": "https://api.github.com/repos/facebook/react/git/trees/c3b2f6cab2521fe8be6ceb84ca6e614fc86addad" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/a0a8e060f0a7681abbad222fdd2a0c6e9943185d", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/ckRIACgkQWCcTbp05\ndTJo0Q/+LBIgbUD4ORK150MXzleKcy2bmmenA8oJDbNJnVe+WU03JsY30O8xIap8\nm6bSKl29KfJqkh77dPe385DaByxfDe0kdm3NBjUJhWxz56tixOB7yvBGU3droPmn\nQUxbcOFP/KWUj6nv+zCRvMOM8/omj0DeTbT8oQGL4AsrT3/RwMzQXG78hp/mE+qe\nbsQOOEww13ZpMoRS5776apBU3Va2gQ7hzpL0Fy1u28iS2DdzsPRXhjZsS4iHEfN/\nC9ogoycwwvXoA0+2fNSlExCzSfFbjnHD1yns6TXK0I98+UpkjZOoaxHXYlAMtgk+\nijplfasF75Bt59dvQdu6F3Hm5H98gLgwe6GOPumxHidcBs+Q5kNAHG4g4Y23QVrs\njj9Av0dEyxQanPLZt6PBtMeULP8oQGuEzuxvCCz7Q6SbbZnzk53SvjzlLPQCHO9Z\noCU3OU+9nOqen52jZt2xH+sRSxvnBnWKHuyuZycQz8gFQeu0CvGt6X+7nTQc0TTy\nKshAbJqoShQyq2QWH7y4xAUiuSsSyNWhTMaMa6a2N7/GFLpBDfOFORYWoXCyOsIW\nzxTdfXgfkfmyVP4spRIeUCHGLmpheJU3grG1nfia19rBQNSZqqE1cZFHGdSi7DO8\nwltWAu/IZye7KG3s9oSwxUC2s7lq2eG7NxeeKQ8KCKrJMr5Xafg=\n=5WKu\n-----END PGP SIGNATURE-----", + "payload": "tree c3b2f6cab2521fe8be6ceb84ca6e614fc86addad\nparent af1c54ed8f5a528028eac4512f5a33f143a5c5e1\nauthor eps1lon 1608290578 +0100\ncommitter eps1lon 1608290578 +0100\n\nUse statefulStore serializer in \"inline error/warning\" tests\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/a0a8e060f0a7681abbad222fdd2a0c6e9943185d", + "html_url": "https://github.com/facebook/react/commit/a0a8e060f0a7681abbad222fdd2a0c6e9943185d", + "comments_url": "https://api.github.com/repos/facebook/react/commits/a0a8e060f0a7681abbad222fdd2a0c6e9943185d/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "af1c54ed8f5a528028eac4512f5a33f143a5c5e1", + "url": "https://api.github.com/repos/facebook/react/commits/af1c54ed8f5a528028eac4512f5a33f143a5c5e1", + "html_url": "https://github.com/facebook/react/commit/af1c54ed8f5a528028eac4512f5a33f143a5c5e1" + } + ] + }, + { + "sha": "5b5d2c52ae2b02e57e9bbfb95cc55933a51ed79d", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjViNWQyYzUyYWUyYjAyZTU3ZTliYmZiOTVjYzU1OTMzYTUxZWQ3OWQ=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-18T11:27:22Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-18T11:27:22Z" + }, + "message": "Fix flow issues", + "tree": { + "sha": "da0e5f6c1164d81a0ccbfa4910101d86a0ccda59", + "url": "https://api.github.com/repos/facebook/react/git/trees/da0e5f6c1164d81a0ccbfa4910101d86a0ccda59" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/5b5d2c52ae2b02e57e9bbfb95cc55933a51ed79d", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/ckhoACgkQWCcTbp05\ndTI7xQ//fo+/xEv/NpQEdB+EVwXIS4GByuyOE4ZW8KLKcK+xyPpwYz+rzOwgw02t\nyyBZpuSgQ3F1QwUeRDJYxBSzUZeToKAkUzMBuSPDsnehy2sIjn/0NTAZjATwDaL1\npP+kMe4hyhH/+Hb++SNnN0ldg670g98eFUtSx5bV8i0DqSPhtk/aBBZXI0NSmUPS\nDRxhrfB5srQlLlNCE92wFf/W0Mmhni0+fqpTh4JjUGHZdoajp7/FMud+HeXJrUaS\nqF2WyYitCTqtPYHIhiffdyGUy9SYxPNS40r6IWzpcQgEBPQ5qAPmrAzLIAMhM+de\nTCamA797+qG6+XGB/KPrQ/d7sIel0cDDyJFyJA2JXpy7RWNxL1rI27/a7e3ZhRyg\nF8YtbaEiSuM58oqfTkB0nlDRlRtyPMjf6VW/8lsrxDdsgD+DnibFi+mTa1TDNvPr\n9mRvGz08NcvLQ6WoDoj3kgm4yFNL/Cd7YEkGsim2+gxQs9lcbmiAx5LB7vtISyHP\nPA5Db+6ndh7xEET+s+MhPtapPnZZ0C9FZyKEUcyZJWo8n0XErF2sG9xykeHcetSW\nOdJTR8A0a6uoLbLfwTCrliSZmXNeKT6vJhfKYcDRg56iHGqEklXbrK+AC7pi/TEN\nx8s1asUGeoe9iNoH4sOCz0Y1cvAD/KSFEmOABZvu+ChC2ksA2bE=\n=qIHU\n-----END PGP SIGNATURE-----", + "payload": "tree da0e5f6c1164d81a0ccbfa4910101d86a0ccda59\nparent a0a8e060f0a7681abbad222fdd2a0c6e9943185d\nauthor eps1lon 1608290842 +0100\ncommitter eps1lon 1608290842 +0100\n\nFix flow issues\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/5b5d2c52ae2b02e57e9bbfb95cc55933a51ed79d", + "html_url": "https://github.com/facebook/react/commit/5b5d2c52ae2b02e57e9bbfb95cc55933a51ed79d", + "comments_url": "https://api.github.com/repos/facebook/react/commits/5b5d2c52ae2b02e57e9bbfb95cc55933a51ed79d/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "a0a8e060f0a7681abbad222fdd2a0c6e9943185d", + "url": "https://api.github.com/repos/facebook/react/commits/a0a8e060f0a7681abbad222fdd2a0c6e9943185d", + "html_url": "https://github.com/facebook/react/commit/a0a8e060f0a7681abbad222fdd2a0c6e9943185d" + } + ] + }, + { + "sha": "4a8738371577f8d4cb8222c1fe49580f47206bdc", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjRhODczODM3MTU3N2Y4ZDRjYjgyMjJjMWZlNDk1ODBmNDcyMDZiZGM=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T13:27:39Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T13:27:39Z" + }, + "message": "Refactored treeContext tests to use inline snapshots and Jest serializer", + "tree": { + "sha": "177aab2fa080508dd16c3f9c7ad1ff36b13e40ad", + "url": "https://api.github.com/repos/facebook/react/git/trees/177aab2fa080508dd16c3f9c7ad1ff36b13e40ad" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/4a8738371577f8d4cb8222c1fe49580f47206bdc", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/4a8738371577f8d4cb8222c1fe49580f47206bdc", + "html_url": "https://github.com/facebook/react/commit/4a8738371577f8d4cb8222c1fe49580f47206bdc", + "comments_url": "https://api.github.com/repos/facebook/react/commits/4a8738371577f8d4cb8222c1fe49580f47206bdc/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "5b5d2c52ae2b02e57e9bbfb95cc55933a51ed79d", + "url": "https://api.github.com/repos/facebook/react/commits/5b5d2c52ae2b02e57e9bbfb95cc55933a51ed79d", + "html_url": "https://github.com/facebook/react/commit/5b5d2c52ae2b02e57e9bbfb95cc55933a51ed79d" + } + ] + }, + { + "sha": "781d8b7775fd0aa619d60471939da3a7573d5fba", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjc4MWQ4Yjc3NzVmZDBhYTYxOWQ2MDQ3MTkzOWRhM2E3NTczZDVmYmE=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T15:56:55Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T15:56:55Z" + }, + "message": "Inline warnings/errors should respect component filters\n\nAdjusting filters should also update errors/warnings.\n\nAlso optimized the filter update flow by adding a REMOVE_ALL operation.\n\nLots of new tests added.", + "tree": { + "sha": "26ab0ffec17099d37d8a7bc89e19944682284ddd", + "url": "https://api.github.com/repos/facebook/react/git/trees/26ab0ffec17099d37d8a7bc89e19944682284ddd" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/781d8b7775fd0aa619d60471939da3a7573d5fba", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/781d8b7775fd0aa619d60471939da3a7573d5fba", + "html_url": "https://github.com/facebook/react/commit/781d8b7775fd0aa619d60471939da3a7573d5fba", + "comments_url": "https://api.github.com/repos/facebook/react/commits/781d8b7775fd0aa619d60471939da3a7573d5fba/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "4a8738371577f8d4cb8222c1fe49580f47206bdc", + "url": "https://api.github.com/repos/facebook/react/commits/4a8738371577f8d4cb8222c1fe49580f47206bdc", + "html_url": "https://github.com/facebook/react/commit/4a8738371577f8d4cb8222c1fe49580f47206bdc" + } + ] + }, + { + "sha": "e69c0b4f9a38f1dff6f1d29403bc7503be929e80", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmU2OWMwYjRmOWEzOGYxZGZmNmYxZDI5NDAzYmM3NTAzYmU5MjllODA=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T16:18:28Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T16:18:28Z" + }, + "message": "Add error/warning counts to serialized store snapshot\n\nThis lets us remove ugly expect-map-to-be statements", + "tree": { + "sha": "fb54811e8b4dd6f6ea7a3a4587856f79a2601999", + "url": "https://api.github.com/repos/facebook/react/git/trees/fb54811e8b4dd6f6ea7a3a4587856f79a2601999" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/e69c0b4f9a38f1dff6f1d29403bc7503be929e80", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/e69c0b4f9a38f1dff6f1d29403bc7503be929e80", + "html_url": "https://github.com/facebook/react/commit/e69c0b4f9a38f1dff6f1d29403bc7503be929e80", + "comments_url": "https://api.github.com/repos/facebook/react/commits/e69c0b4f9a38f1dff6f1d29403bc7503be929e80/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "781d8b7775fd0aa619d60471939da3a7573d5fba", + "url": "https://api.github.com/repos/facebook/react/commits/781d8b7775fd0aa619d60471939da3a7573d5fba", + "html_url": "https://github.com/facebook/react/commit/781d8b7775fd0aa619d60471939da3a7573d5fba" + } + ] + }, + { + "sha": "bc788d82066ece29b858a072c8da262babf78202", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmJjNzg4ZDgyMDY2ZWNlMjliODU4YTA3MmM4ZGEyNjJiYWJmNzgyMDI=", + "commit": { + "author": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-18T17:45:47Z" + }, + "committer": { + "name": "eps1lon", + "email": "silbermann.sebastian@gmail.com", + "date": "2020-12-18T17:45:47Z" + }, + "message": "Add failing test for uncommitted renders", + "tree": { + "sha": "6dc204c237700e69a1355e75d4dd6a686f591493", + "url": "https://api.github.com/repos/facebook/react/git/trees/6dc204c237700e69a1355e75d4dd6a686f591493" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/bc788d82066ece29b858a072c8da262babf78202", + "comment_count": 0, + "verification": { + "verified": true, + "reason": "valid", + "signature": "-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEdEe9h5RnyYkE768zWCcTbp05dTIFAl/c6ssACgkQWCcTbp05\ndTI/HBAAsX1qdq2tZs+1ifhylxrcH1UvbR+AaDZ1dDp7RHXiJ23WnQURRiFq1u2g\nQpBv6wLTxTi58dLXG0VQbw6rwvYvjseramKirD5t4JefEInGWp2cP6HOykW66GrX\nFK90Ut4CXNsJcNkXj/DQoSJYRPxgf8Rq0AbH3KODPTgRNTjFDgv6bJtsFJtGIQbV\nAljLW2SMrT8C7q+kt8NWsRyMrpvMCU1Nn5DrFxclBIni4lNj5dwmx6AgTC/5UKiN\nX0DyXtc2Y6/6fV78AN6wvghUHoZ1wxfMb0RA1LxEbWFfE/Lepz9uTjbRgbzG9l9p\nF59SKT0tbHB2CulqpKoy4LxT6TP9l2D8ucdfgm39nO+C5c96QVEDvOOaA5rFAVd5\nL9rjcqjkttbNyGFcFCfETY5IDed5ss/7K/LjcbY09JtVSRFbD2At8qVT9pK3J6hm\ni5Q78X1wq/3dWbL0zdDe19lyhKDxRwUNVdi5rpdiSl/Z2iP0OXFq3t1wyqvT1hNS\nZ3nrIKUqVIIm3P12YtXxupd37wlWQboR4CVIzld8zaqyIjA0/aMSDKaSc0cjLfdj\nImB0r93Phx9RrxDnfRNSzw2dqJOv2r+9GKCrJLt2UBJccLvCmYncygsmKCrtM1im\nWU0X3N0Ty+y0QMIDzhT9z7pA6Wf3+Nrszk5dirQAZhc/NsoaNhA=\n=WqmE\n-----END PGP SIGNATURE-----", + "payload": "tree 6dc204c237700e69a1355e75d4dd6a686f591493\nparent e69c0b4f9a38f1dff6f1d29403bc7503be929e80\nauthor eps1lon 1608313547 +0100\ncommitter eps1lon 1608313547 +0100\n\nAdd failing test for uncommitted renders\n", + "verified_at": "2024-11-11T02:11:17Z" + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/bc788d82066ece29b858a072c8da262babf78202", + "html_url": "https://github.com/facebook/react/commit/bc788d82066ece29b858a072c8da262babf78202", + "comments_url": "https://api.github.com/repos/facebook/react/commits/bc788d82066ece29b858a072c8da262babf78202/comments", + "author": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "committer": { + "login": "eps1lon", + "id": 12292047, + "node_id": "MDQ6VXNlcjEyMjkyMDQ3", + "avatar_url": "https://avatars.githubusercontent.com/u/12292047?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/eps1lon", + "html_url": "https://github.com/eps1lon", + "followers_url": "https://api.github.com/users/eps1lon/followers", + "following_url": "https://api.github.com/users/eps1lon/following{/other_user}", + "gists_url": "https://api.github.com/users/eps1lon/gists{/gist_id}", + "starred_url": "https://api.github.com/users/eps1lon/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/eps1lon/subscriptions", + "organizations_url": "https://api.github.com/users/eps1lon/orgs", + "repos_url": "https://api.github.com/users/eps1lon/repos", + "events_url": "https://api.github.com/users/eps1lon/events{/privacy}", + "received_events_url": "https://api.github.com/users/eps1lon/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "parents": [ + { + "sha": "e69c0b4f9a38f1dff6f1d29403bc7503be929e80", + "url": "https://api.github.com/repos/facebook/react/commits/e69c0b4f9a38f1dff6f1d29403bc7503be929e80", + "html_url": "https://github.com/facebook/react/commit/e69c0b4f9a38f1dff6f1d29403bc7503be929e80" + } + ] + }, + { + "sha": "22c3f4bf903ec46e4915557d605f0433a3963900", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjIyYzNmNGJmOTAzZWM0NmU0OTE1NTU3ZDYwNWYwNDMzYTM5NjM5MDA=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T18:52:42Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T18:52:42Z" + }, + "message": "Don't send errors/warnings for suspended or errored subtrees", + "tree": { + "sha": "b3f879545ab4eda881278f299ca522e74a977c1b", + "url": "https://api.github.com/repos/facebook/react/git/trees/b3f879545ab4eda881278f299ca522e74a977c1b" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/22c3f4bf903ec46e4915557d605f0433a3963900", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/22c3f4bf903ec46e4915557d605f0433a3963900", + "html_url": "https://github.com/facebook/react/commit/22c3f4bf903ec46e4915557d605f0433a3963900", + "comments_url": "https://api.github.com/repos/facebook/react/commits/22c3f4bf903ec46e4915557d605f0433a3963900/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "bc788d82066ece29b858a072c8da262babf78202", + "url": "https://api.github.com/repos/facebook/react/commits/bc788d82066ece29b858a072c8da262babf78202", + "html_url": "https://github.com/facebook/react/commit/bc788d82066ece29b858a072c8da262babf78202" + } + ] + }, + { + "sha": "b9fa573d12b29f79db11663cf40b84c66ce37d03", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOmI5ZmE1NzNkMTJiMjlmNzlkYjExNjYzY2Y0MGI4NGM2NmNlMzdkMDM=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T19:18:19Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T19:18:19Z" + }, + "message": "Wait to flush errors/warnings until the next commit; it's safer", + "tree": { + "sha": "2b76ccc4079a89072bb22d7ba99941fe0463258f", + "url": "https://api.github.com/repos/facebook/react/git/trees/2b76ccc4079a89072bb22d7ba99941fe0463258f" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/b9fa573d12b29f79db11663cf40b84c66ce37d03", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/b9fa573d12b29f79db11663cf40b84c66ce37d03", + "html_url": "https://github.com/facebook/react/commit/b9fa573d12b29f79db11663cf40b84c66ce37d03", + "comments_url": "https://api.github.com/repos/facebook/react/commits/b9fa573d12b29f79db11663cf40b84c66ce37d03/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "22c3f4bf903ec46e4915557d605f0433a3963900", + "url": "https://api.github.com/repos/facebook/react/commits/22c3f4bf903ec46e4915557d605f0433a3963900", + "html_url": "https://github.com/facebook/react/commit/22c3f4bf903ec46e4915557d605f0433a3963900" + } + ] + }, + { + "sha": "4c9bf6508bd8c0bf61802b1da7641f6295d19f68", + "node_id": "MDY6Q29tbWl0MTUyODQ3MzAwOjRjOWJmNjUwOGJkOGMwYmY2MTgwMmIxZGE3NjQxZjYyOTVkMTlmNjg=", + "commit": { + "author": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T20:10:42Z" + }, + "committer": { + "name": "Brian Vaughn", + "email": "bvaughn@fb.com", + "date": "2020-12-18T20:10:42Z" + }, + "message": "Remove separate 'errorsAndWarnings' event in favor of 'mutations'\n\nThis avoids the case of one being updated without the other.", + "tree": { + "sha": "9484071f785ba18dfeeec8f4d6069ca9915b02c6", + "url": "https://api.github.com/repos/facebook/react/git/trees/9484071f785ba18dfeeec8f4d6069ca9915b02c6" + }, + "url": "https://api.github.com/repos/facebook/react/git/commits/4c9bf6508bd8c0bf61802b1da7641f6295d19f68", + "comment_count": 0, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null, + "verified_at": null + } + }, + "url": "https://api.github.com/repos/facebook/react/commits/4c9bf6508bd8c0bf61802b1da7641f6295d19f68", + "html_url": "https://github.com/facebook/react/commit/4c9bf6508bd8c0bf61802b1da7641f6295d19f68", + "comments_url": "https://api.github.com/repos/facebook/react/commits/4c9bf6508bd8c0bf61802b1da7641f6295d19f68/comments", + "author": null, + "committer": null, + "parents": [ + { + "sha": "b9fa573d12b29f79db11663cf40b84c66ce37d03", + "url": "https://api.github.com/repos/facebook/react/commits/b9fa573d12b29f79db11663cf40b84c66ce37d03", + "html_url": "https://github.com/facebook/react/commit/b9fa573d12b29f79db11663cf40b84c66ce37d03" + } + ] + } +] \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/clients/pull_request_review_comment_reply.json b/src/test/resources/com/spotify/github/v3/clients/pull_request_review_comment_reply.json new file mode 100644 index 00000000..361fcded --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/clients/pull_request_review_comment_reply.json @@ -0,0 +1,56 @@ +{ + "url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1", + "pull_request_review_id": 42, + "id": 10, + "node_id": "MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDEw", + "diff_hunk": "@@ -16,33 +16,40 @@ public class Connection : IConnection...", + "path": "file1.txt", + "position": 1, + "original_position": 4, + "commit_id": "6dcb09b5b57875f334f61aebed695e2e4193db5e", + "original_commit_id": "9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840", + "in_reply_to_id": 426899381, + "user": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "body": "Great stuff!", + "created_at": "2011-04-14T16:00:49Z", + "updated_at": "2011-04-14T16:00:49Z", + "html_url": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1", + "pull_request_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1", + "author_association": "NONE", + "_links": { + "self": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1" + }, + "html": { + "href": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1" + }, + "pull_request": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/1" + } + }, + "start_line": 1, + "original_start_line": 1, + "start_side": "RIGHT", + "line": 2, + "original_line": 2, + "side": "RIGHT" + } diff --git a/src/test/resources/com/spotify/github/v3/githubapp/access-token.json b/src/test/resources/com/spotify/github/v3/githubapp/access-token.json new file mode 100644 index 00000000..0085c41a --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/githubapp/access-token.json @@ -0,0 +1,4 @@ +{ + "token": "ghs_16C7e42F292c6912E7710c838347Ae178B4a", + "expires_at": "2024-08-10T05:54:58Z" +} diff --git a/src/test/resources/com/spotify/github/v3/githubapp/authenticated-app.json b/src/test/resources/com/spotify/github/v3/githubapp/authenticated-app.json new file mode 100644 index 00000000..b5dc8eab --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/githubapp/authenticated-app.json @@ -0,0 +1,43 @@ +{ + "id": 1, + "slug": "octoapp", + "node_id": "MDExOkludGVncmF0aW9uMQ==", + "owner": { + "login": "github", + "id": 1, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=", + "url": "https://api.github.com/orgs/github", + "repos_url": "https://api.github.com/orgs/github/repos", + "events_url": "https://api.github.com/orgs/github/events", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "html_url": "https://github.com/github", + "followers_url": "https://api.github.com/users/github/followers", + "following_url": "https://api.github.com/users/github/following{/other_user}", + "gists_url": "https://api.github.com/users/github/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github/subscriptions", + "organizations_url": "https://api.github.com/users/github/orgs", + "received_events_url": "https://api.github.com/users/github/received_events", + "type": "User", + "site_admin": true + }, + "name": "Octocat App", + "description": "Test GitHub App", + "external_url": "https://example.com", + "html_url": "https://github.com/apps/octoapp", + "created_at": "2017-07-08T16:18:44-04:00", + "updated_at": "2017-07-08T16:18:44-04:00", + "permissions": { + "metadata": "read", + "contents": "read", + "issues": "write", + "single_file": "write" + }, + "events": ["push", "pull_request"], + "installations_count": 5, + "client_id": "Iv1.8a61f9b3a7aba766", + "client_secret": "1726be1638095a19edd134c77bde3aa2ece1e5d8", + "webhook_secret": "e340154128314309424b7c8e90325147d99fdafa", + "pem": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAuEPzOUE+kiEH1WLiMeBytTEF856j0hgg...\n-----END RSA PRIVATE KEY-----" +} diff --git a/src/test/resources/com/spotify/github/v3/issues/issue.json b/src/test/resources/com/spotify/github/v3/issues/issue.json index 00e88af9..768fcdbf 100644 --- a/src/test/resources/com/spotify/github/v3/issues/issue.json +++ b/src/test/resources/com/spotify/github/v3/issues/issue.json @@ -1,5 +1,6 @@ { - "id": 1, + "id": 2, + "node_id": "MDU6SXNzdWUx", "url": "https://api.github.com/repos/octocat/Hello-World/issues/1347", "repository_url": "https://api.github.com/repos/octocat/Hello-World", "labels_url": "https://api.github.com/repos/octocat/Hello-World/issues/1347/labels{/name}", @@ -13,6 +14,7 @@ "user": { "login": "octocat", "id": 1, + "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", @@ -31,14 +33,19 @@ }, "labels": [ { + "id": 208045946, + "node_id": "MDU6TGFiZWwyMDgwNDU5NDY=", "url": "https://api.github.com/repos/octocat/Hello-World/labels/bug", "name": "bug", - "color": "f29513" + "description": "Something isn't working", + "color": "f29513", + "default": true } ], "assignee": { "login": "octocat", "id": 1, + "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", @@ -55,11 +62,34 @@ "type": "User", "site_admin": false }, + "assignees": [ + { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + } + ], "milestone": { "url": "https://api.github.com/repos/octocat/Hello-World/milestones/1", "html_url": "https://github.com/octocat/Hello-World/milestones/v1.0", "labels_url": "https://api.github.com/repos/octocat/Hello-World/milestones/1/labels", "id": 1002604, + "node_id": "MDk6TWlsZXN0b25lMTAwMjYwNA==", "number": 1, "state": "open", "title": "v1.0", @@ -67,6 +97,7 @@ "creator": { "login": "octocat", "id": 1, + "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", @@ -90,7 +121,8 @@ "closed_at": "2013-02-12T13:22:01Z", "due_on": "2012-10-09T23:39:01Z" }, - "locked": false, + "locked": true, + "active_lock_reason": "too heated", "comments": 0, "pull_request": { "url": "https://api.github.com/repos/octocat/Hello-World/pulls/1347", @@ -100,5 +132,27 @@ }, "closed_at": null, "created_at": "2011-04-22T13:33:48Z", - "updated_at": "2011-04-22T13:33:48Z" + "updated_at": "2011-04-22T13:33:48Z", + "closed_by": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "author_association": "COLLABORATOR", + "state_reason": "completed" } \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/prs/pull_request.json b/src/test/resources/com/spotify/github/v3/prs/pull_request.json index b996f1d2..7d1014db 100644 --- a/src/test/resources/com/spotify/github/v3/prs/pull_request.json +++ b/src/test/resources/com/spotify/github/v3/prs/pull_request.json @@ -69,6 +69,16 @@ "closed_at": "2013-02-12T13:22:01Z", "due_on": "2012-10-09T23:39:01Z" }, + "labels": [ + { + "id": 42, + "node_id": "MDU6TGFiZWw0Mg==", + "url": "https://api.github.com/repos/batterseapower/pinyin-toolkit/labels/bug", + "name": "bug", + "color": "ff0000", + "default": true + } + ], "locked": false, "created_at": "2011-01-26T19:01:12Z", "updated_at": "2011-01-26T19:01:12Z", diff --git a/src/test/resources/com/spotify/github/v3/prs/pull_request_automerge_disabled.json b/src/test/resources/com/spotify/github/v3/prs/pull_request_automerge_disabled.json new file mode 100644 index 00000000..e4d01d2a --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/prs/pull_request_automerge_disabled.json @@ -0,0 +1,359 @@ +{ + "url": "https://api.github.com/repos/spotify/github-java-client/pulls/226", + "id": 2439836648, + "node_id": "PR_kwDODynaQc6RbPPo", + "html_url": "https://github.com/spotify/github-java-client/pull/226", + "diff_url": "https://github.com/spotify/github-java-client/pull/226.diff", + "patch_url": "https://github.com/spotify/github-java-client/pull/226.patch", + "issue_url": "https://api.github.com/repos/spotify/github-java-client/issues/226", + "number": 226, + "state": "open", + "locked": false, + "title": "feat: Add auto_merge field to the PR class", + "user": { + "login": "octocat", + "id": 1445581, + "node_id": "MDQ6VXNlcjE0NDU1ODE=", + "avatar_url": "https://avatars.githubusercontent.com/u/1445581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "body": "Adds the auto_merge field to the PR class", + "created_at": "2025-04-04T15:21:13Z", + "updated_at": "2025-04-04T15:23:48Z", + "closed_at": null, + "merged_at": null, + "merge_commit_sha": "62862b387d19968ab0777ac90044929ece5b94ca", + "assignee": null, + "assignees": [], + "requested_reviewers": [], + "requested_teams": [], + "labels": [], + "milestone": null, + "draft": true, + "commits_url": "https://api.github.com/repos/spotify/github-java-client/pulls/226/commits", + "review_comments_url": "https://api.github.com/repos/spotify/github-java-client/pulls/226/comments", + "review_comment_url": "https://api.github.com/repos/spotify/github-java-client/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/spotify/github-java-client/issues/226/comments", + "statuses_url": "https://api.github.com/repos/spotify/github-java-client/statuses/881ef333d1ffc01869b666f13d3b37d7af92b9a2", + "head": { + "label": "spotify:feat/add-auto-merge-field", + "ref": "feat/add-auto-merge-field", + "sha": "881ef333d1ffc01869b666f13d3b37d7af92b9a2", + "user": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "repo": { + "id": 254401089, + "node_id": "MDEwOlJlcG9zaXRvcnkyNTQ0MDEwODk=", + "name": "github-java-client", + "full_name": "spotify/github-java-client", + "private": false, + "owner": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/spotify/github-java-client", + "description": "A Java client to Github API", + "fork": false, + "url": "https://api.github.com/repos/spotify/github-java-client", + "forks_url": "https://api.github.com/repos/spotify/github-java-client/forks", + "keys_url": "https://api.github.com/repos/spotify/github-java-client/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/spotify/github-java-client/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/spotify/github-java-client/teams", + "hooks_url": "https://api.github.com/repos/spotify/github-java-client/hooks", + "issue_events_url": "https://api.github.com/repos/spotify/github-java-client/issues/events{/number}", + "events_url": "https://api.github.com/repos/spotify/github-java-client/events", + "assignees_url": "https://api.github.com/repos/spotify/github-java-client/assignees{/user}", + "branches_url": "https://api.github.com/repos/spotify/github-java-client/branches{/branch}", + "tags_url": "https://api.github.com/repos/spotify/github-java-client/tags", + "blobs_url": "https://api.github.com/repos/spotify/github-java-client/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/spotify/github-java-client/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/spotify/github-java-client/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/spotify/github-java-client/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/spotify/github-java-client/statuses/{sha}", + "languages_url": "https://api.github.com/repos/spotify/github-java-client/languages", + "stargazers_url": "https://api.github.com/repos/spotify/github-java-client/stargazers", + "contributors_url": "https://api.github.com/repos/spotify/github-java-client/contributors", + "subscribers_url": "https://api.github.com/repos/spotify/github-java-client/subscribers", + "subscription_url": "https://api.github.com/repos/spotify/github-java-client/subscription", + "commits_url": "https://api.github.com/repos/spotify/github-java-client/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/spotify/github-java-client/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/spotify/github-java-client/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/spotify/github-java-client/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/spotify/github-java-client/contents/{+path}", + "compare_url": "https://api.github.com/repos/spotify/github-java-client/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/spotify/github-java-client/merges", + "archive_url": "https://api.github.com/repos/spotify/github-java-client/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/spotify/github-java-client/downloads", + "issues_url": "https://api.github.com/repos/spotify/github-java-client/issues{/number}", + "pulls_url": "https://api.github.com/repos/spotify/github-java-client/pulls{/number}", + "milestones_url": "https://api.github.com/repos/spotify/github-java-client/milestones{/number}", + "notifications_url": "https://api.github.com/repos/spotify/github-java-client/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/spotify/github-java-client/labels{/name}", + "releases_url": "https://api.github.com/repos/spotify/github-java-client/releases{/id}", + "deployments_url": "https://api.github.com/repos/spotify/github-java-client/deployments", + "created_at": "2020-04-09T14:55:56Z", + "updated_at": "2025-03-29T17:20:38Z", + "pushed_at": "2025-04-04T15:20:42Z", + "git_url": "git://github.com/spotify/github-java-client.git", + "ssh_url": "git@github.com:spotify/github-java-client.git", + "clone_url": "https://github.com/spotify/github-java-client.git", + "svn_url": "https://github.com/spotify/github-java-client", + "homepage": "", + "size": 3067, + "stargazers_count": 144, + "watchers_count": 144, + "language": "Java", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": true, + "has_discussions": false, + "forks_count": 93, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 23, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 93, + "open_issues": 23, + "watchers": 144, + "default_branch": "master" + } + }, + "base": { + "label": "spotify:master", + "ref": "master", + "sha": "bcd052d1b2508ae1e97cbeea16f198ce796743ad", + "user": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "repo": { + "id": 254401089, + "node_id": "MDEwOlJlcG9zaXRvcnkyNTQ0MDEwODk=", + "name": "github-java-client", + "full_name": "spotify/github-java-client", + "private": false, + "owner": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/spotify/github-java-client", + "description": "A Java client to Github API", + "fork": false, + "url": "https://api.github.com/repos/spotify/github-java-client", + "forks_url": "https://api.github.com/repos/spotify/github-java-client/forks", + "keys_url": "https://api.github.com/repos/spotify/github-java-client/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/spotify/github-java-client/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/spotify/github-java-client/teams", + "hooks_url": "https://api.github.com/repos/spotify/github-java-client/hooks", + "issue_events_url": "https://api.github.com/repos/spotify/github-java-client/issues/events{/number}", + "events_url": "https://api.github.com/repos/spotify/github-java-client/events", + "assignees_url": "https://api.github.com/repos/spotify/github-java-client/assignees{/user}", + "branches_url": "https://api.github.com/repos/spotify/github-java-client/branches{/branch}", + "tags_url": "https://api.github.com/repos/spotify/github-java-client/tags", + "blobs_url": "https://api.github.com/repos/spotify/github-java-client/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/spotify/github-java-client/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/spotify/github-java-client/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/spotify/github-java-client/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/spotify/github-java-client/statuses/{sha}", + "languages_url": "https://api.github.com/repos/spotify/github-java-client/languages", + "stargazers_url": "https://api.github.com/repos/spotify/github-java-client/stargazers", + "contributors_url": "https://api.github.com/repos/spotify/github-java-client/contributors", + "subscribers_url": "https://api.github.com/repos/spotify/github-java-client/subscribers", + "subscription_url": "https://api.github.com/repos/spotify/github-java-client/subscription", + "commits_url": "https://api.github.com/repos/spotify/github-java-client/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/spotify/github-java-client/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/spotify/github-java-client/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/spotify/github-java-client/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/spotify/github-java-client/contents/{+path}", + "compare_url": "https://api.github.com/repos/spotify/github-java-client/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/spotify/github-java-client/merges", + "archive_url": "https://api.github.com/repos/spotify/github-java-client/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/spotify/github-java-client/downloads", + "issues_url": "https://api.github.com/repos/spotify/github-java-client/issues{/number}", + "pulls_url": "https://api.github.com/repos/spotify/github-java-client/pulls{/number}", + "milestones_url": "https://api.github.com/repos/spotify/github-java-client/milestones{/number}", + "notifications_url": "https://api.github.com/repos/spotify/github-java-client/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/spotify/github-java-client/labels{/name}", + "releases_url": "https://api.github.com/repos/spotify/github-java-client/releases{/id}", + "deployments_url": "https://api.github.com/repos/spotify/github-java-client/deployments", + "created_at": "2020-04-09T14:55:56Z", + "updated_at": "2025-03-29T17:20:38Z", + "pushed_at": "2025-04-04T15:20:42Z", + "git_url": "git://github.com/spotify/github-java-client.git", + "ssh_url": "git@github.com:spotify/github-java-client.git", + "clone_url": "https://github.com/spotify/github-java-client.git", + "svn_url": "https://github.com/spotify/github-java-client", + "homepage": "", + "size": 3067, + "stargazers_count": 144, + "watchers_count": 144, + "language": "Java", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": true, + "has_discussions": false, + "forks_count": 93, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 23, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 93, + "open_issues": 23, + "watchers": 144, + "default_branch": "master" + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/spotify/github-java-client/pulls/226" + }, + "html": { + "href": "https://github.com/spotify/github-java-client/pull/226" + }, + "issue": { + "href": "https://api.github.com/repos/spotify/github-java-client/issues/226" + }, + "comments": { + "href": "https://api.github.com/repos/spotify/github-java-client/issues/226/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/spotify/github-java-client/pulls/226/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/spotify/github-java-client/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/spotify/github-java-client/pulls/226/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/spotify/github-java-client/statuses/881ef333d1ffc01869b666f13d3b37d7af92b9a2" + } + }, + "author_association": "MEMBER", + "auto_merge": null, + "active_lock_reason": null, + "merged": false, + "mergeable": true, + "rebaseable": true, + "mergeable_state": "blocked", + "merged_by": null, + "comments": 1, + "review_comments": 0, + "maintainer_can_modify": false, + "commits": 1, + "additions": 54, + "deletions": 2, + "changed_files": 2 +} \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/prs/pull_request_automerge_enabled.json b/src/test/resources/com/spotify/github/v3/prs/pull_request_automerge_enabled.json new file mode 100644 index 00000000..6d71517a --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/prs/pull_request_automerge_enabled.json @@ -0,0 +1,384 @@ +{ + "url": "https://api.github.com/repos/spotify/github-java-client/pulls/226", + "id": 2439836648, + "node_id": "PR_kwDODynaQc6RbPPo", + "html_url": "https://github.com/spotify/github-java-client/pull/226", + "diff_url": "https://github.com/spotify/github-java-client/pull/226.diff", + "patch_url": "https://github.com/spotify/github-java-client/pull/226.patch", + "issue_url": "https://api.github.com/repos/spotify/github-java-client/issues/226", + "number": 226, + "state": "open", + "locked": false, + "title": "feat: Add auto_merge field to the PR class", + "user": { + "login": "octocat", + "id": 1445581, + "node_id": "MDQ6VXNlcjE0NDU1ODE=", + "avatar_url": "https://avatars.githubusercontent.com/u/1445581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "body": "Adds the auto_merge field to the PR class", + "created_at": "2025-04-04T15:21:13Z", + "updated_at": "2025-04-05T07:45:19Z", + "closed_at": null, + "merged_at": null, + "merge_commit_sha": "62862b387d19968ab0777ac90044929ece5b94ca", + "assignee": null, + "assignees": [], + "requested_reviewers": [], + "requested_teams": [], + "labels": [], + "milestone": null, + "draft": false, + "commits_url": "https://api.github.com/repos/spotify/github-java-client/pulls/226/commits", + "review_comments_url": "https://api.github.com/repos/spotify/github-java-client/pulls/226/comments", + "review_comment_url": "https://api.github.com/repos/spotify/github-java-client/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/spotify/github-java-client/issues/226/comments", + "statuses_url": "https://api.github.com/repos/spotify/github-java-client/statuses/881ef333d1ffc01869b666f13d3b37d7af92b9a2", + "head": { + "label": "spotify:feat/add-auto-merge-field", + "ref": "feat/add-auto-merge-field", + "sha": "881ef333d1ffc01869b666f13d3b37d7af92b9a2", + "user": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "repo": { + "id": 254401089, + "node_id": "MDEwOlJlcG9zaXRvcnkyNTQ0MDEwODk=", + "name": "github-java-client", + "full_name": "spotify/github-java-client", + "private": false, + "owner": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/spotify/github-java-client", + "description": "A Java client to Github API", + "fork": false, + "url": "https://api.github.com/repos/spotify/github-java-client", + "forks_url": "https://api.github.com/repos/spotify/github-java-client/forks", + "keys_url": "https://api.github.com/repos/spotify/github-java-client/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/spotify/github-java-client/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/spotify/github-java-client/teams", + "hooks_url": "https://api.github.com/repos/spotify/github-java-client/hooks", + "issue_events_url": "https://api.github.com/repos/spotify/github-java-client/issues/events{/number}", + "events_url": "https://api.github.com/repos/spotify/github-java-client/events", + "assignees_url": "https://api.github.com/repos/spotify/github-java-client/assignees{/user}", + "branches_url": "https://api.github.com/repos/spotify/github-java-client/branches{/branch}", + "tags_url": "https://api.github.com/repos/spotify/github-java-client/tags", + "blobs_url": "https://api.github.com/repos/spotify/github-java-client/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/spotify/github-java-client/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/spotify/github-java-client/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/spotify/github-java-client/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/spotify/github-java-client/statuses/{sha}", + "languages_url": "https://api.github.com/repos/spotify/github-java-client/languages", + "stargazers_url": "https://api.github.com/repos/spotify/github-java-client/stargazers", + "contributors_url": "https://api.github.com/repos/spotify/github-java-client/contributors", + "subscribers_url": "https://api.github.com/repos/spotify/github-java-client/subscribers", + "subscription_url": "https://api.github.com/repos/spotify/github-java-client/subscription", + "commits_url": "https://api.github.com/repos/spotify/github-java-client/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/spotify/github-java-client/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/spotify/github-java-client/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/spotify/github-java-client/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/spotify/github-java-client/contents/{+path}", + "compare_url": "https://api.github.com/repos/spotify/github-java-client/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/spotify/github-java-client/merges", + "archive_url": "https://api.github.com/repos/spotify/github-java-client/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/spotify/github-java-client/downloads", + "issues_url": "https://api.github.com/repos/spotify/github-java-client/issues{/number}", + "pulls_url": "https://api.github.com/repos/spotify/github-java-client/pulls{/number}", + "milestones_url": "https://api.github.com/repos/spotify/github-java-client/milestones{/number}", + "notifications_url": "https://api.github.com/repos/spotify/github-java-client/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/spotify/github-java-client/labels{/name}", + "releases_url": "https://api.github.com/repos/spotify/github-java-client/releases{/id}", + "deployments_url": "https://api.github.com/repos/spotify/github-java-client/deployments", + "created_at": "2020-04-09T14:55:56Z", + "updated_at": "2025-03-29T17:20:38Z", + "pushed_at": "2025-04-04T15:20:42Z", + "git_url": "git://github.com/spotify/github-java-client.git", + "ssh_url": "git@github.com:spotify/github-java-client.git", + "clone_url": "https://github.com/spotify/github-java-client.git", + "svn_url": "https://github.com/spotify/github-java-client", + "homepage": "", + "size": 3067, + "stargazers_count": 144, + "watchers_count": 144, + "language": "Java", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": true, + "has_discussions": false, + "forks_count": 93, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 23, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 93, + "open_issues": 23, + "watchers": 144, + "default_branch": "master" + } + }, + "base": { + "label": "spotify:master", + "ref": "master", + "sha": "bcd052d1b2508ae1e97cbeea16f198ce796743ad", + "user": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "repo": { + "id": 254401089, + "node_id": "MDEwOlJlcG9zaXRvcnkyNTQ0MDEwODk=", + "name": "github-java-client", + "full_name": "spotify/github-java-client", + "private": false, + "owner": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/spotify/github-java-client", + "description": "A Java client to Github API", + "fork": false, + "url": "https://api.github.com/repos/spotify/github-java-client", + "forks_url": "https://api.github.com/repos/spotify/github-java-client/forks", + "keys_url": "https://api.github.com/repos/spotify/github-java-client/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/spotify/github-java-client/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/spotify/github-java-client/teams", + "hooks_url": "https://api.github.com/repos/spotify/github-java-client/hooks", + "issue_events_url": "https://api.github.com/repos/spotify/github-java-client/issues/events{/number}", + "events_url": "https://api.github.com/repos/spotify/github-java-client/events", + "assignees_url": "https://api.github.com/repos/spotify/github-java-client/assignees{/user}", + "branches_url": "https://api.github.com/repos/spotify/github-java-client/branches{/branch}", + "tags_url": "https://api.github.com/repos/spotify/github-java-client/tags", + "blobs_url": "https://api.github.com/repos/spotify/github-java-client/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/spotify/github-java-client/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/spotify/github-java-client/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/spotify/github-java-client/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/spotify/github-java-client/statuses/{sha}", + "languages_url": "https://api.github.com/repos/spotify/github-java-client/languages", + "stargazers_url": "https://api.github.com/repos/spotify/github-java-client/stargazers", + "contributors_url": "https://api.github.com/repos/spotify/github-java-client/contributors", + "subscribers_url": "https://api.github.com/repos/spotify/github-java-client/subscribers", + "subscription_url": "https://api.github.com/repos/spotify/github-java-client/subscription", + "commits_url": "https://api.github.com/repos/spotify/github-java-client/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/spotify/github-java-client/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/spotify/github-java-client/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/spotify/github-java-client/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/spotify/github-java-client/contents/{+path}", + "compare_url": "https://api.github.com/repos/spotify/github-java-client/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/spotify/github-java-client/merges", + "archive_url": "https://api.github.com/repos/spotify/github-java-client/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/spotify/github-java-client/downloads", + "issues_url": "https://api.github.com/repos/spotify/github-java-client/issues{/number}", + "pulls_url": "https://api.github.com/repos/spotify/github-java-client/pulls{/number}", + "milestones_url": "https://api.github.com/repos/spotify/github-java-client/milestones{/number}", + "notifications_url": "https://api.github.com/repos/spotify/github-java-client/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/spotify/github-java-client/labels{/name}", + "releases_url": "https://api.github.com/repos/spotify/github-java-client/releases{/id}", + "deployments_url": "https://api.github.com/repos/spotify/github-java-client/deployments", + "created_at": "2020-04-09T14:55:56Z", + "updated_at": "2025-03-29T17:20:38Z", + "pushed_at": "2025-04-04T15:20:42Z", + "git_url": "git://github.com/spotify/github-java-client.git", + "ssh_url": "git@github.com:spotify/github-java-client.git", + "clone_url": "https://github.com/spotify/github-java-client.git", + "svn_url": "https://github.com/spotify/github-java-client", + "homepage": "", + "size": 3067, + "stargazers_count": 144, + "watchers_count": 144, + "language": "Java", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": true, + "has_discussions": false, + "forks_count": 93, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 23, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 93, + "open_issues": 23, + "watchers": 144, + "default_branch": "master" + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/spotify/github-java-client/pulls/226" + }, + "html": { + "href": "https://github.com/spotify/github-java-client/pull/226" + }, + "issue": { + "href": "https://api.github.com/repos/spotify/github-java-client/issues/226" + }, + "comments": { + "href": "https://api.github.com/repos/spotify/github-java-client/issues/226/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/spotify/github-java-client/pulls/226/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/spotify/github-java-client/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/spotify/github-java-client/pulls/226/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/spotify/github-java-client/statuses/881ef333d1ffc01869b666f13d3b37d7af92b9a2" + } + }, + "author_association": "MEMBER", + "auto_merge": { + "enabled_by": { + "login": "octocat", + "id": 1445581, + "node_id": "MDQ6VXNlcjE0NDU1ODE=", + "avatar_url": "https://avatars.githubusercontent.com/u/1445581?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "merge_method": "squash", + "commit_title": "feat: Add auto_merge field to the PR class (#226)", + "commit_message": "" + }, + "active_lock_reason": null, + "merged": false, + "mergeable": true, + "rebaseable": true, + "mergeable_state": "blocked", + "merged_by": null, + "comments": 1, + "review_comments": 0, + "maintainer_can_modify": false, + "commits": 1, + "additions": 54, + "deletions": 2, + "changed_files": 2 +} \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/prs/pull_request_long_id.json b/src/test/resources/com/spotify/github/v3/prs/pull_request_long_id.json new file mode 100644 index 00000000..fa4ef17f --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/prs/pull_request_long_id.json @@ -0,0 +1,389 @@ +{ + "url": "https://api.github.com/repos/spotify/scio/pulls/5525", + "id": 2459198527, + "node_id": "PR_kwDOAfa55s6COrI0", + "html_url": "https://github.com/spotify/scio/pull/5525", + "diff_url": "https://github.com/spotify/scio/pull/5525.diff", + "patch_url": "https://github.com/spotify/scio/pull/5525.patch", + "issue_url": "https://api.github.com/repos/spotify/scio/issues/5525", + "number": 5525, + "state": "open", + "locked": false, + "title": "Update beam to 2.61", + "user": { + "login": "RustedBones", + "id": 2845540, + "node_id": "MDQ6VXNlcjI4NDU1NDA=", + "avatar_url": "https://avatars.githubusercontent.com/u/2845540?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/RustedBones", + "html_url": "https://github.com/RustedBones", + "followers_url": "https://api.github.com/users/RustedBones/followers", + "following_url": "https://api.github.com/users/RustedBones/following{/other_user}", + "gists_url": "https://api.github.com/users/RustedBones/gists{/gist_id}", + "starred_url": "https://api.github.com/users/RustedBones/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/RustedBones/subscriptions", + "organizations_url": "https://api.github.com/users/RustedBones/orgs", + "repos_url": "https://api.github.com/users/RustedBones/repos", + "events_url": "https://api.github.com/users/RustedBones/events{/privacy}", + "received_events_url": "https://api.github.com/users/RustedBones/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "body": "Leverages upstream [changes](https://github.com/apache/beam/pull/32482) available for BQ:\r\nAnnotated BQ typed avro translation leverages logical-type to have symmetric read/write. This fixes integration testfailure introduced in https://github.com/spotify/scio/pull/5523", + "created_at": "2024-11-18T10:56:55Z", + "updated_at": "2024-11-19T17:06:12Z", + "closed_at": null, + "merged_at": null, + "merge_commit_sha": null, + "assignee": null, + "assignees": [ + + ], + "requested_reviewers": [ + + ], + "requested_teams": [ + + ], + "labels": [ + + ], + "milestone": null, + "draft": true, + "commits_url": "https://api.github.com/repos/spotify/scio/pulls/5525/commits", + "review_comments_url": "https://api.github.com/repos/spotify/scio/pulls/5525/comments", + "review_comment_url": "https://api.github.com/repos/spotify/scio/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/spotify/scio/issues/5525/comments", + "statuses_url": "https://api.github.com/repos/spotify/scio/statuses/f74c7f420282f584acd2fb5964202e5b525c3ab8", + "head": { + "label": "spotify:beam-2.61", + "ref": "beam-2.61", + "sha": "f74c7f420282f584acd2fb5964202e5b525c3ab8", + "user": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "repo": { + "id": 32946662, + "node_id": "MDEwOlJlcG9zaXRvcnkzMjk0NjY2Mg==", + "name": "scio", + "full_name": "spotify/scio", + "private": false, + "owner": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/spotify/scio", + "description": "A Scala API for Apache Beam and Google Cloud Dataflow.", + "fork": false, + "url": "https://api.github.com/repos/spotify/scio", + "forks_url": "https://api.github.com/repos/spotify/scio/forks", + "keys_url": "https://api.github.com/repos/spotify/scio/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/spotify/scio/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/spotify/scio/teams", + "hooks_url": "https://api.github.com/repos/spotify/scio/hooks", + "issue_events_url": "https://api.github.com/repos/spotify/scio/issues/events{/number}", + "events_url": "https://api.github.com/repos/spotify/scio/events", + "assignees_url": "https://api.github.com/repos/spotify/scio/assignees{/user}", + "branches_url": "https://api.github.com/repos/spotify/scio/branches{/branch}", + "tags_url": "https://api.github.com/repos/spotify/scio/tags", + "blobs_url": "https://api.github.com/repos/spotify/scio/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/spotify/scio/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/spotify/scio/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/spotify/scio/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/spotify/scio/statuses/{sha}", + "languages_url": "https://api.github.com/repos/spotify/scio/languages", + "stargazers_url": "https://api.github.com/repos/spotify/scio/stargazers", + "contributors_url": "https://api.github.com/repos/spotify/scio/contributors", + "subscribers_url": "https://api.github.com/repos/spotify/scio/subscribers", + "subscription_url": "https://api.github.com/repos/spotify/scio/subscription", + "commits_url": "https://api.github.com/repos/spotify/scio/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/spotify/scio/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/spotify/scio/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/spotify/scio/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/spotify/scio/contents/{+path}", + "compare_url": "https://api.github.com/repos/spotify/scio/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/spotify/scio/merges", + "archive_url": "https://api.github.com/repos/spotify/scio/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/spotify/scio/downloads", + "issues_url": "https://api.github.com/repos/spotify/scio/issues{/number}", + "pulls_url": "https://api.github.com/repos/spotify/scio/pulls{/number}", + "milestones_url": "https://api.github.com/repos/spotify/scio/milestones{/number}", + "notifications_url": "https://api.github.com/repos/spotify/scio/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/spotify/scio/labels{/name}", + "releases_url": "https://api.github.com/repos/spotify/scio/releases{/id}", + "deployments_url": "https://api.github.com/repos/spotify/scio/deployments", + "created_at": "2015-03-26T19:07:34Z", + "updated_at": "2024-11-25T02:07:06Z", + "pushed_at": "2024-11-22T09:28:47Z", + "git_url": "git://github.com/spotify/scio.git", + "ssh_url": "git@github.com:spotify/scio.git", + "clone_url": "https://github.com/spotify/scio.git", + "svn_url": "https://github.com/spotify/scio", + "homepage": "https://spotify.github.io/scio", + "size": 70358, + "stargazers_count": 2559, + "watchers_count": 2559, + "language": "Scala", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": true, + "has_discussions": true, + "forks_count": 514, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 143, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + "batch", + "beam", + "bigquery", + "data", + "dataflow", + "google-cloud", + "ml", + "scala", + "scio", + "streaming" + ], + "visibility": "public", + "forks": 514, + "open_issues": 143, + "watchers": 2559, + "default_branch": "main" + } + }, + "base": { + "label": "spotify:main", + "ref": "main", + "sha": "49f43b028dbd5df9dfb5362714c9fbd76e9019db", + "user": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "repo": { + "id": 32946662, + "node_id": "MDEwOlJlcG9zaXRvcnkzMjk0NjY2Mg==", + "name": "scio", + "full_name": "spotify/scio", + "private": false, + "owner": { + "login": "spotify", + "id": 251374, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjI1MTM3NA==", + "avatar_url": "https://avatars.githubusercontent.com/u/251374?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/spotify", + "html_url": "https://github.com/spotify", + "followers_url": "https://api.github.com/users/spotify/followers", + "following_url": "https://api.github.com/users/spotify/following{/other_user}", + "gists_url": "https://api.github.com/users/spotify/gists{/gist_id}", + "starred_url": "https://api.github.com/users/spotify/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/spotify/subscriptions", + "organizations_url": "https://api.github.com/users/spotify/orgs", + "repos_url": "https://api.github.com/users/spotify/repos", + "events_url": "https://api.github.com/users/spotify/events{/privacy}", + "received_events_url": "https://api.github.com/users/spotify/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "html_url": "https://github.com/spotify/scio", + "description": "A Scala API for Apache Beam and Google Cloud Dataflow.", + "fork": false, + "url": "https://api.github.com/repos/spotify/scio", + "forks_url": "https://api.github.com/repos/spotify/scio/forks", + "keys_url": "https://api.github.com/repos/spotify/scio/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/spotify/scio/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/spotify/scio/teams", + "hooks_url": "https://api.github.com/repos/spotify/scio/hooks", + "issue_events_url": "https://api.github.com/repos/spotify/scio/issues/events{/number}", + "events_url": "https://api.github.com/repos/spotify/scio/events", + "assignees_url": "https://api.github.com/repos/spotify/scio/assignees{/user}", + "branches_url": "https://api.github.com/repos/spotify/scio/branches{/branch}", + "tags_url": "https://api.github.com/repos/spotify/scio/tags", + "blobs_url": "https://api.github.com/repos/spotify/scio/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/spotify/scio/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/spotify/scio/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/spotify/scio/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/spotify/scio/statuses/{sha}", + "languages_url": "https://api.github.com/repos/spotify/scio/languages", + "stargazers_url": "https://api.github.com/repos/spotify/scio/stargazers", + "contributors_url": "https://api.github.com/repos/spotify/scio/contributors", + "subscribers_url": "https://api.github.com/repos/spotify/scio/subscribers", + "subscription_url": "https://api.github.com/repos/spotify/scio/subscription", + "commits_url": "https://api.github.com/repos/spotify/scio/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/spotify/scio/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/spotify/scio/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/spotify/scio/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/spotify/scio/contents/{+path}", + "compare_url": "https://api.github.com/repos/spotify/scio/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/spotify/scio/merges", + "archive_url": "https://api.github.com/repos/spotify/scio/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/spotify/scio/downloads", + "issues_url": "https://api.github.com/repos/spotify/scio/issues{/number}", + "pulls_url": "https://api.github.com/repos/spotify/scio/pulls{/number}", + "milestones_url": "https://api.github.com/repos/spotify/scio/milestones{/number}", + "notifications_url": "https://api.github.com/repos/spotify/scio/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/spotify/scio/labels{/name}", + "releases_url": "https://api.github.com/repos/spotify/scio/releases{/id}", + "deployments_url": "https://api.github.com/repos/spotify/scio/deployments", + "created_at": "2015-03-26T19:07:34Z", + "updated_at": "2024-11-25T02:07:06Z", + "pushed_at": "2024-11-22T09:28:47Z", + "git_url": "git://github.com/spotify/scio.git", + "ssh_url": "git@github.com:spotify/scio.git", + "clone_url": "https://github.com/spotify/scio.git", + "svn_url": "https://github.com/spotify/scio", + "homepage": "https://spotify.github.io/scio", + "size": 70358, + "stargazers_count": 2559, + "watchers_count": 2559, + "language": "Scala", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": true, + "has_discussions": true, + "forks_count": 514, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 143, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + "batch", + "beam", + "bigquery", + "data", + "dataflow", + "google-cloud", + "ml", + "scala", + "scio", + "streaming" + ], + "visibility": "public", + "forks": 514, + "open_issues": 143, + "watchers": 2559, + "default_branch": "main" + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/spotify/scio/pulls/5525" + }, + "html": { + "href": "https://github.com/spotify/scio/pull/5525" + }, + "issue": { + "href": "https://api.github.com/repos/spotify/scio/issues/5525" + }, + "comments": { + "href": "https://api.github.com/repos/spotify/scio/issues/5525/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/spotify/scio/pulls/5525/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/spotify/scio/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/spotify/scio/pulls/5525/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/spotify/scio/statuses/f74c7f420282f584acd2fb5964202e5b525c3ab8" + } + }, + "author_association": "CONTRIBUTOR", + "auto_merge": null, + "active_lock_reason": null, + "merged": false, + "mergeable": false, + "rebaseable": false, + "mergeable_state": "dirty", + "merged_by": null, + "comments": 1, + "review_comments": 1, + "maintainer_can_modify": false, + "commits": 3, + "additions": 89, + "deletions": 152, + "changed_files": 12 +} \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/prs/review_long_id.json b/src/test/resources/com/spotify/github/v3/prs/review_long_id.json new file mode 100644 index 00000000..4dcca923 --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/prs/review_long_id.json @@ -0,0 +1,38 @@ +{ + "id": 2459198580, + "node_id": "MDE3OlB1bGxSZXF1ZXN0UmV2aWV3ODA=", + "user": { + "login": "octocat", + "id": 1, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "body": "Here is the body for the review.", + "submitted_at": "2019-11-17T17:43:43Z", + "commit_id": "ecdd80bb57125d7ba9641ffaa4d7d2c19d3f3091", + "state": "APPROVED", + "html_url": "https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80", + "pull_request_url": "https://api.github.com/repos/octocat/Hello-World/pulls/12", + "_links": { + "html": { + "href": "https://github.com/octocat/Hello-World/pull/12#pullrequestreview-80" + }, + "pull_request": { + "href": "https://api.github.com/repos/octocat/Hello-World/pulls/12" + } + } +} \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/search/issues-long-id.json b/src/test/resources/com/spotify/github/v3/search/issues-long-id.json new file mode 100644 index 00000000..428a6431 --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/search/issues-long-id.json @@ -0,0 +1,72 @@ +{ + "total_count": 280, + "incomplete_results": false, + "items": [ + { + "url": "https://api.github.com/repos/spotify/scio/issues/5514", + "repository_url": "https://api.github.com/repos/spotify/scio", + "labels_url": "https://api.github.com/repos/spotify/scio/issues/5514/labels{/name}", + "comments_url": "https://api.github.com/repos/spotify/scio/issues/5514/comments", + "events_url": "https://api.github.com/repos/spotify/scio/issues/5514/events", + "html_url": "https://github.com/spotify/scio/issues/5514", + "id": 2592843837, + "node_id": "I_kwDOAfa55s6ai6g9", + "number": 5514, + "title": "Benchmark BigTable maxPendingRequests", + "user": { + "login": "kellen", + "id": 486691, + "node_id": "MDQ6VXNlcjQ4NjY5MQ==", + "avatar_url": "https://avatars.githubusercontent.com/u/486691?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/kellen", + "html_url": "https://github.com/kellen", + "followers_url": "https://api.github.com/users/kellen/followers", + "following_url": "https://api.github.com/users/kellen/following{/other_user}", + "gists_url": "https://api.github.com/users/kellen/gists{/gist_id}", + "starred_url": "https://api.github.com/users/kellen/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/kellen/subscriptions", + "organizations_url": "https://api.github.com/users/kellen/orgs", + "repos_url": "https://api.github.com/users/kellen/repos", + "events_url": "https://api.github.com/users/kellen/events{/privacy}", + "received_events_url": "https://api.github.com/users/kellen/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "labels": [ + + ], + "state": "open", + "locked": false, + "assignee": null, + "assignees": [ + + ], + "milestone": null, + "comments": 0, + "created_at": "2024-10-16T19:23:04Z", + "updated_at": "2024-10-16T19:23:40Z", + "closed_at": null, + "author_association": "CONTRIBUTOR", + "active_lock_reason": null, + "body": "Internal spotify discussions suggest that the default `maxPendingRequests=1` may no longer be a good default and a higher value (e.g. `6`) may make more sense for batch. \r\n\r\nWe should write some benchmarks to verify and update the documentation and/or defaults based on the benchmark results.\r\n", + "closed_by": null, + "reactions": { + "url": "https://api.github.com/repos/spotify/scio/issues/5514/reactions", + "total_count": 0, + "+1": 0, + "-1": 0, + "laugh": 0, + "hooray": 0, + "confused": 0, + "heart": 0, + "rocket": 0, + "eyes": 0 + }, + "timeline_url": "https://api.github.com/repos/spotify/scio/issues/5514/timeline", + "performed_via_github_app": null, + "state_reason": null + } + ] +} diff --git a/src/test/resources/com/spotify/github/v3/search/issues.json b/src/test/resources/com/spotify/github/v3/search/issues.json index 3c2cf3c7..9e6f5fb9 100644 --- a/src/test/resources/com/spotify/github/v3/search/issues.json +++ b/src/test/resources/com/spotify/github/v3/search/issues.json @@ -32,9 +32,12 @@ }, "labels": [ { + "id": 42, + "node_id": "MDU6TGFiZWw0Mg==", "url": "https://api.github.com/repos/batterseapower/pinyin-toolkit/labels/bug", "name": "bug", - "color": "ff0000" + "color": "ff0000", + "default": true } ], "state": "open", diff --git a/src/test/resources/com/spotify/github/v3/workflows/workflows-get-workflow-response.json b/src/test/resources/com/spotify/github/v3/workflows/workflows-get-workflow-response.json new file mode 100644 index 00000000..a636603a --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/workflows/workflows-get-workflow-response.json @@ -0,0 +1,13 @@ +{ + "id": 161335, + "node_id": "MDg6V29ya2Zsb3cxNjEzMzU=", + "name": "CI", + "path": ".github/workflows/blank.yaml", + "state": "active", + "created_at": "2020-01-08T23:48:37.000-08:00", + "updated_at": "2020-01-08T23:50:21.000-08:00", + "deleted_at": "2020-01-09T23:50:21.000-08:00", + "url": "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/161335", + "html_url": "https://github.com/octo-org/octo-repo/blob/master/.github/workflows/161335", + "badge_url": "https://github.com/octo-org/octo-repo/workflows/CI/badge.svg" +} \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/workflows/workflows-list-workflows-response.json b/src/test/resources/com/spotify/github/v3/workflows/workflows-list-workflows-response.json new file mode 100644 index 00000000..d572e59f --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/workflows/workflows-list-workflows-response.json @@ -0,0 +1,31 @@ +{ + "total_count": 2, + "workflows": [ + { + "id": 161335, + "node_id": "MDg6V29ya2Zsb3cxNjEzMzU=", + "name": "CI", + "path": ".github/workflows/blank.yaml", + "state": "active", + "created_at": "2020-01-08T23:48:37.000-08:00", + "updated_at": "2020-01-08T23:50:21.000-08:00", + "deleted_at": "2020-01-09T23:50:21.000-08:00", + "url": "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/161335", + "html_url": "https://github.com/octo-org/octo-repo/blob/master/.github/workflows/161335", + "badge_url": "https://github.com/octo-org/octo-repo/workflows/CI/badge.svg" + }, + { + "id": 269289, + "node_id": "MDE4OldvcmtmbG93IFNlY29uZGFyeTI2OTI4OQ==", + "name": "Linter", + "path": ".github/workflows/linter.yaml", + "state": "active", + "created_at": "2020-01-08T23:48:37.000-08:00", + "updated_at": "2020-01-08T23:50:21.000-08:00", + "deleted_at": "2020-01-09T23:50:21.000-08:00", + "url": "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/269289", + "html_url": "https://github.com/octo-org/octo-repo/blob/master/.github/workflows/269289", + "badge_url": "https://github.com/octo-org/octo-repo/workflows/Linter/badge.svg" + } + ] +} \ No newline at end of file