99import java .util .Collections ;
1010import java .util .List ;
1111import java .util .Objects ;
12+ import java .util .stream .StreamSupport ;
1213import org .jspecify .annotations .NonNull ;
1314import org .jspecify .annotations .Nullable ;
1415import org .slf4j .Logger ;
@@ -32,8 +33,8 @@ public class GitHubClient {
3233 private final ObjectMapper objectMapper ;
3334
3435 /**
35- * Default constructor that initializes the GitHub client with the base URL and headers.
36- * It retrieves the GitHub token from the environment variable GITHUB_TOKEN.
36+ * Default constructor that initializes the GitHub client with the base URL and headers. It retrieves the GitHub
37+ * token from the environment variable GITHUB_TOKEN.
3738 */
3839 public GitHubClient (@ Value ("${github.token}" ) String githubToken ) {
3940 Builder builder = RestClient .builder ()
@@ -56,7 +57,7 @@ public Repository getRepository(@NonNull final String org, @NonNull final String
5657 .uri ("/repos/{org}/{repo}" , org , repo )
5758 .retrieve ()
5859 .toEntity (String .class );
59- if (!repoEntity .getStatusCode ().is2xxSuccessful ()) {
60+ if (!repoEntity .getStatusCode ().is2xxSuccessful ()) {
6061 throw new IllegalStateException ("Failed to get repo from GitHub: " + repoEntity .getBody ());
6162 }
6263 final JsonNode repoJsonNode ;
@@ -71,7 +72,7 @@ public Repository getRepository(@NonNull final String org, @NonNull final String
7172 .uri ("/repos/{org}/{repo}/languages" , org , repo )
7273 .retrieve ()
7374 .toEntity (String .class );
74- if (!languagesEntity .getStatusCode ().is2xxSuccessful ()) {
75+ if (!languagesEntity .getStatusCode ().is2xxSuccessful ()) {
7576 throw new IllegalStateException ("Failed to get languages from GitHub: " + languagesEntity .getBody ());
7677 }
7778 final JsonNode languagesJsonNode ;
@@ -92,25 +93,25 @@ public Repository getRepository(@NonNull final String org, @NonNull final String
9293 fieldNames .forEach (fieldName -> {
9394 final int count = languagesJsonNode .get (fieldName ).asInt ();
9495 final double percentage = (double ) count / languageSum * 100 ;
95- if (percentage > 33.0 ) {
96+ if (percentage > 33.0 ) {
9697 languageTags .add (fieldName );
9798 }
9899 });
99100 final long stars = repoJsonNode .get ("stargazers_count" ).asLong ();
100101
101-
102102 return new Repository (org , repo , imageUrl , languageTags , stars );
103103 }
104104
105- public List <Issue > getIssues (@ NonNull final Repository repository , @ NonNull final String label , @ Nullable List <String > excludedIdentifiers ) {
105+ public List <Issue > getIssues (@ NonNull final Repository repository , @ NonNull final String label ,
106+ @ Nullable List <String > excludedIdentifiers ) {
106107 Objects .requireNonNull (repository , "repository must not be null" );
107108 Objects .requireNonNull (label , "label must not be null" );
108109 final List <Issue > issues = new ArrayList <>();
109110 final ResponseEntity <String > entity = restClient .get ()
110111 .uri ("/repos/{org}/{repo}/issues?labels={label}" , repository .org (), repository .name (), label )
111112 .retrieve ()
112113 .toEntity (String .class );
113- if (!entity .getStatusCode ().is2xxSuccessful ()) {
114+ if (!entity .getStatusCode ().is2xxSuccessful ()) {
114115 throw new IllegalStateException ("Failed to get issues from GitHub: " + entity .getBody ());
115116 }
116117 final JsonNode jsonNode ;
@@ -119,57 +120,57 @@ public List<Issue> getIssues(@NonNull final Repository repository, @NonNull fina
119120 } catch (Exception e ) {
120121 throw new IllegalStateException ("Failed to parse issues from GitHub: " + entity .getBody (), e );
121122 }
122- if (!jsonNode .isArray ()) {
123- throw new IllegalStateException ("Expected an array of issues from GitHub, but got: " + entity .getBody ());
123+ if (!jsonNode .isArray ()) {
124+ throw new IllegalStateException ("Expected an array of issues from GitHub, but got: " + entity .getBody ());
124125 }
125126 jsonNode .iterator ().forEachRemaining (issueNode -> {
126- if (!issueNode .has ("html_url" )) {
127- throw new IllegalStateException ("Expected an issue to have an html_url, but got: " + issueNode );
128- }
129- final JsonNode urlNode = issueNode .get ("html_url" );
130- if (!urlNode .isTextual ()) {
131- throw new IllegalStateException ("Expected an issue's html_url to be a string, but got: " + urlNode );
132- }
133- final String url = urlNode .asText ();
134-
135- if (!issueNode .has ("title" )) {
127+ if (!issueNode .has ("html_url" )) {
128+ throw new IllegalStateException ("Expected an issue to have an html_url, but got: " + issueNode );
129+ }
130+ final JsonNode urlNode = issueNode .get ("html_url" );
131+ if (!urlNode .isTextual ()) {
132+ throw new IllegalStateException ("Expected an issue's html_url to be a string, but got: " + urlNode );
133+ }
134+ final String url = urlNode .asText ();
135+
136+ if (!issueNode .has ("title" )) {
136137 throw new IllegalStateException ("Expected an issue to have an title, but got: " + issueNode );
137138 }
138139 final JsonNode titleNode = issueNode .get ("title" );
139- if (!titleNode .isTextual ()) {
140+ if (!titleNode .isTextual ()) {
140141 throw new IllegalStateException ("Expected an issue's title to be a string, but got: " + urlNode );
141142 }
142143 final String title = titleNode .asText ();
143144
144- if (!issueNode .has ("number" )) {
145+ if (!issueNode .has ("number" )) {
145146 throw new IllegalStateException ("Expected an issue to have an number, but got: " + issueNode );
146147 }
147148 final JsonNode numberNode = issueNode .get ("number" );
148- if (!numberNode .isInt ()) {
149+ if (!numberNode .isInt ()) {
149150 throw new IllegalStateException ("Expected an issue's number to be a int, but got: " + urlNode );
150151 }
151152 final int number = numberNode .asInt ();
152153
153154 final boolean isAssigned = issueNode .has ("assignee" ) && !issueNode .get ("assignee" ).isNull ();
154155 final boolean isClosed = issueNode .get ("state" ).asText ().equals ("closed" );
155156 final List <String > labels = new ArrayList <>();
156- if (issueNode .has ("labels" )) {
157+ if (issueNode .has ("labels" )) {
157158 issueNode .get ("labels" ).forEach (labelNode -> {
158- if (!labelNode .has ("name" )) {
159+ if (!labelNode .has ("name" )) {
159160 throw new IllegalStateException ("Expected a label to have a name, but got: " + labelNode );
160161 }
161162 final JsonNode nameNode = labelNode .get ("name" );
162- if (!nameNode .isTextual ()) {
163+ if (!nameNode .isTextual ()) {
163164 throw new IllegalStateException ("Expected a label's name to be a string, but got: " + nameNode );
164165 }
165166 labels .add (nameNode .asText ());
166167 });
167168 }
168169
169-
170- final Issue issue = new Issue ( title , Integer . valueOf ( number ). toString (), repository , url , isAssigned , isClosed , labels );
170+ final Issue issue = new Issue ( title , Integer . valueOf ( number ). toString (), repository , url , isAssigned ,
171+ isClosed , labels );
171172 if (excludedIdentifiers == null || !excludedIdentifiers .contains (issue .identifier ())) {
172- issues .add (issue );
173+ issues .add (issue );
173174 }
174175 });
175176 return Collections .unmodifiableList (issues );
@@ -181,17 +182,18 @@ public List<Contributor> getContributors(@NonNull final Repository repository) {
181182
182183 public List <Contributor > getContributors (@ NonNull final Repository repository , final int page ) {
183184 Objects .requireNonNull (repository , "repository must not be null" );
184- if (page < 0 ) {
185+ if (page < 0 ) {
185186 throw new IllegalArgumentException ("page must be greater than or equal to 0" );
186187 }
187188
188189 List <Contributor > contributors = new ArrayList <>();
189190
190191 final ResponseEntity <String > entity = restClient .get ()
191- .uri ("/repos/{org}/{repo}/contributors?per_page=100&page={page}" , repository .org (), repository .name (), page )
192+ .uri ("/repos/{org}/{repo}/contributors?per_page=100&page={page}" , repository .org (), repository .name (),
193+ page )
192194 .retrieve ()
193195 .toEntity (String .class );
194- if (!entity .getStatusCode ().is2xxSuccessful ()) {
196+ if (!entity .getStatusCode ().is2xxSuccessful ()) {
195197 throw new IllegalStateException ("Failed to get issues from GitHub: " + entity .getBody ());
196198 }
197199 final JsonNode jsonNode ;
@@ -200,35 +202,40 @@ public List<Contributor> getContributors(@NonNull final Repository repository, f
200202 } catch (Exception e ) {
201203 throw new IllegalStateException ("Failed to parse issues from GitHub: " + entity .getBody (), e );
202204 }
203- if (!jsonNode .isArray ()) {
205+ if (!jsonNode .isArray ()) {
204206 throw new IllegalStateException ("Expected an array of issues from GitHub, but got: " + entity .getBody ());
205207 }
206208
207- jsonNode .forEach (contributorNode -> {
208- if (!contributorNode .has ("login" )) {
209- throw new IllegalStateException ("Expected a contributor to have a login, but got: " + contributorNode );
210- }
211- final JsonNode loginNode = contributorNode .get ("login" );
212- if (!loginNode .isTextual ()) {
213- throw new IllegalStateException ("Expected a contributor's login to be a string, but got: " + loginNode );
214- }
215- final String userName = loginNode .asText ();
216-
217- if (!contributorNode .has ("avatar_url" )) {
218- throw new IllegalStateException ("Expected a avatar_url to have an contributions, but got: " + contributorNode );
219- }
220- final JsonNode avatarUrlNode = contributorNode .get ("avatar_url" );
221- if (!avatarUrlNode .isTextual ()) {
222- throw new IllegalStateException ("Expected a contributor's avatar_url to be a string, but got: " + avatarUrlNode );
223- }
224- final String avatarUrl = avatarUrlNode .asText ();
209+ StreamSupport .stream (jsonNode .spliterator (), false )
210+ .filter (node -> node .has ("type" ) && !node .get ("type" ).asText ().equals ("Bot" ))
211+ .forEach (contributorNode -> {
212+ if (!contributorNode .has ("login" )) {
213+ throw new IllegalStateException (
214+ "Expected a contributor to have a login, but got: " + contributorNode );
215+ }
216+ final JsonNode loginNode = contributorNode .get ("login" );
217+ if (!loginNode .isTextual ()) {
218+ throw new IllegalStateException (
219+ "Expected a contributor's login to be a string, but got: " + loginNode );
220+ }
221+ final String userName = loginNode .asText ();
225222
226- final Contributor contributor = new Contributor (userName , avatarUrl );
227- contributors .add (contributor );
228- });
223+ if (!contributorNode .has ("avatar_url" )) {
224+ throw new IllegalStateException (
225+ "Expected a avatar_url to have an contributions, but got: " + contributorNode );
226+ }
227+ final JsonNode avatarUrlNode = contributorNode .get ("avatar_url" );
228+ if (!avatarUrlNode .isTextual ()) {
229+ throw new IllegalStateException (
230+ "Expected a contributor's avatar_url to be a string, but got: " + avatarUrlNode );
231+ }
232+ final String avatarUrl = avatarUrlNode .asText ();
229233
234+ final Contributor contributor = new Contributor (userName , avatarUrl );
235+ contributors .add (contributor );
236+ });
230237
231- if (!contributors .isEmpty ()) {
238+ if (!contributors .isEmpty ()) {
232239 List <Contributor > nextContributors = getContributors (repository , page + 1 );
233240 contributors .addAll (nextContributors );
234241 }
0 commit comments