• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

samsmithnz / RepoAutomation / 3895898324

pending completion
3895898324

push

github

GitHub
Merge pull request #212 from samsmithnz/FixToLanguageTest

333 of 474 branches covered (70.25%)

Branch coverage included in aggregate %.

795 of 893 relevant lines covered (89.03%)

6.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.58
/src/RepoAutomation.Core/APIAccess/GitHubApiAccess.cs
1
using Newtonsoft.Json;
2
using RepoAutomation.Core.Models;
3
using System.Text;
4
using System.Web;
5

6
namespace RepoAutomation.Core.APIAccess;
7

8
public static class GitHubApiAccess
9
{
10

11
    //https://docs.github.com/en/enterprise-cloud@latest/rest/reference/repos
12
    /// <summary>
13
    /// Get a single repo
14
    /// </summary>
15
    /// <param name="clientId"></param>
16
    /// <param name="clientSecret"></param>
17
    /// <param name="owner"></param>
18
    /// <param name="repo"></param>
19
    /// <returns></returns>
20
    public async static Task<Repo?> GetRepo(string? clientId, string? clientSecret, string owner, string repo)
21
    {
8✔
22
        Repo? result = null;
8✔
23
        if (clientId != null && clientSecret != null)
8!
24
        {
8✔
25
            string url = $"https://api.github.com/repos/{owner}/{repo}";
8✔
26
            string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
8✔
27
            if (!string.IsNullOrEmpty(response) &&
8!
28
                response != @"{""message"":""Not Found"",""documentation_url"":""https://docs.github.com/rest/reference/repos#get-a-repository""}")
8✔
29
            {
5✔
30
                dynamic? jsonObj = JsonConvert.DeserializeObject(response);
5✔
31
                result = JsonConvert.DeserializeObject<Repo>(jsonObj?.ToString());
5!
32
                result.RawJSON = jsonObj?.ToString();
5!
33
            }
5✔
34
        }
8✔
35
        return result;
8✔
36
    }
8✔
37

38
    //https://docs.github.com/en/rest/reference/repos#list-repositories-for-a-user
39
    /// <summary>
40
    /// Get a list of repos
41
    /// </summary>
42
    /// <param name="clientId"></param>
43
    /// <param name="clientSecret"></param>
44
    /// <param name="owner"></param>
45
    /// <returns></returns>
46
    public async static Task<List<Repo>?> GetRepos(string? clientId, string? clientSecret, string owner)
47
    {
1✔
48
        List<Repo>? result = new();
1✔
49
        if (clientId != null && clientSecret != null)
1!
50
        {
1✔
51
            string url = $"https://api.github.com/users/{owner}/repos";
1✔
52
            string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
1✔
53
            if (!string.IsNullOrEmpty(response) &&
1!
54
                response != @"{""message"":""Not Found"",""documentation_url"":""https://docs.github.com/rest/reference/repos#get-a-repository""}")
1✔
55
            {
1✔
56
                dynamic? jsonObj = JsonConvert.DeserializeObject(response);
1✔
57
                string? jsonString = jsonObj?.ToString();
1!
58
                if (jsonString != null)
1✔
59
                {
1✔
60
                    result = JsonConvert.DeserializeObject<List<Repo>>(jsonString);
1✔
61
                }
1✔
62
                //Commented out because we are returning a list, and there is no RawJSON property on the list
63
                //result.RawJSON = jsonObj?.ToString();
64
            }
1✔
65
        }
1✔
66
        return result;
1✔
67
    }
1✔
68

69
    /// <summary>
70
    /// Create a new repo
71
    /// </summary>
72
    /// <param name="clientId"></param>
73
    /// <param name="clientSecret"></param>
74
    /// <param name="repo"></param>
75
    /// <param name="allowAutoMerge"></param>
76
    /// <param name="deleteBranchOnMerge"></param>
77
    /// <param name="allowRebaseMerge"></param>
78
    /// <param name="isPrivate"></param>
79
    /// <param name="gitIgnoreTemplate"></param>
80
    /// <returns></returns>
81
    public async static Task<bool> CreateRepo(string? clientId, string? clientSecret,
82
        string repo,
83
        bool allowAutoMerge,
84
        bool deleteBranchOnMerge,
85
        bool allowRebaseMerge,
86
        bool isPrivate,
87
        string gitIgnoreTemplate = "VisualStudio")
88
    {
1✔
89
        if (clientId != null && clientSecret != null)
1!
90
        {
1✔
91
            var body = new
1✔
92
            {
1✔
93
                name = repo,
1✔
94
                allow_auto_merge = allowAutoMerge,
1✔
95
                delete_branch_on_merge = deleteBranchOnMerge,
1✔
96
                allow_rebase_merge = allowRebaseMerge,
1✔
97
                @private = isPrivate,
1✔
98
                auto_init = true,
1✔
99
                gitignore_template = gitIgnoreTemplate,
1✔
100

1✔
101
            };
1✔
102
            StringContent content = new(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
1✔
103
            string url = $"https://api.github.com/user/repos";
1✔
104
            await BaseApiAccess.PostGitHubMessage(url, clientId, clientSecret, content);
1✔
105
        }
1✔
106
        return true;
1✔
107
    }
1✔
108

109
    /// <summary>
110
    /// Update a new repo
111
    /// </summary>
112
    /// <param name="clientId"></param>
113
    /// <param name="clientSecret"></param>
114
    /// <param name="owner"></param>
115
    /// <param name="repo"></param>
116
    /// <param name="allowAutoMerge"></param>
117
    /// <param name="deleteBranchOnMerge"></param>
118
    /// <param name="allowRebaseMerge"></param>
119
    /// <param name="isPrivate"></param>
120
    /// <returns></returns>
121
    public async static Task<bool> UpdateRepo(string? clientId, string? clientSecret,
122
        string owner,
123
        string repo,
124
        bool allowAutoMerge,
125
        bool deleteBranchOnMerge,
126
        bool allowRebaseMerge,
127
        bool isPrivate)
128
    {
1✔
129
        if (clientId != null && clientSecret != null)
1!
130
        {
1✔
131
            var body = new
1✔
132
            {
1✔
133
                name = repo,
1✔
134
                allow_auto_merge = allowAutoMerge,
1✔
135
                delete_branch_on_merge = deleteBranchOnMerge,
1✔
136
                allow_rebase_merge = allowRebaseMerge,
1✔
137
                @private = isPrivate,
1✔
138
                auto_init = true
1✔
139
            };
1✔
140
            StringContent content = new(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
1✔
141
            //https://docs.github.com/en/rest/repos/repos#update-a-repository
142
            string url = $"https://api.github.com/repos/{owner}/{repo}";
1✔
143
            await BaseApiAccess.PatchGitHubMessage(url, clientId, clientSecret, content);
1✔
144
        }
1✔
145
        return true;
1✔
146
    }
1✔
147

148

149

150
    /// <summary>
151
    /// Delete the repo
152
    /// </summary>
153
    /// <param name="clientId"></param>
154
    /// <param name="clientSecret"></param>
155
    /// <param name="owner"></param>
156
    /// <param name="repo"></param>
157
    /// <param name="processErrors"></param>
158
    /// <returns></returns>
159
    public async static Task<bool> DeleteRepo(string? clientId, string? clientSecret, string owner, string repo, bool processErrors = true)
160
    {
3✔
161
        if (clientId != null && clientSecret != null)
3!
162
        {
3✔
163
            string url = $"https://api.github.com/repos/{owner}/{repo}";
3✔
164
            string? response = await BaseApiAccess.DeleteGitHubMessage(url, clientId, clientSecret, processErrors);
3✔
165
            if (string.IsNullOrEmpty(response))
2✔
166
            {
1✔
167
                return false;
1✔
168
            }
169
        }
1✔
170
        return true;
1✔
171
    }
2✔
172

173
    /// <summary>
174
    /// Get a list of all files at a path
175
    /// </summary>
176
    /// <param name="clientId"></param>
177
    /// <param name="clientSecret"></param>
178
    /// <param name="owner"></param>
179
    /// <param name="repo"></param>
180
    /// <param name="path"></param>
181
    /// <returns></returns>
182
    public async static Task<GitHubFile[]?> GetFiles(string? clientId, string? clientSecret,
183
        string owner, string repo, string path)
184
    {
5✔
185
        GitHubFile[]? result = null;
5✔
186
        if (clientId != null && clientSecret != null)
5!
187
        {
5✔
188
            path = HttpUtility.UrlEncode(path);
5✔
189
            string url = $"https://api.github.com/repos/{owner}/{repo}/contents/{path}";
5✔
190
            string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
5✔
191
            if (!string.IsNullOrEmpty(response) &&
5!
192
                !response.Contains(@"""message"":""Not Found"""))
5✔
193
            {
5✔
194
                dynamic? jsonObj = JsonConvert.DeserializeObject(response);
5✔
195
                result = JsonConvert.DeserializeObject<GitHubFile[]>(jsonObj?.ToString());
5!
196
            }
5✔
197
        }
5✔
198
        return result;
5✔
199
    }
5✔
200

201
    /// <summary>
202
    /// Get a file and it's contents
203
    /// </summary>
204
    /// <param name="clientId"></param>
205
    /// <param name="clientSecret"></param>
206
    /// <param name="owner"></param>
207
    /// <param name="repo"></param>
208
    /// <param name="path"></param>
209
    /// <returns></returns>
210
    public async static Task<GitHubFile?> GetFile(string? clientId, string? clientSecret,
211
        string owner, string repo, string path)
212
    {
4✔
213
        GitHubFile? result = null;
4✔
214
        path = HttpUtility.UrlEncode(path);
4✔
215
        string url = $"https://api.github.com/repos/{owner}/{repo}/contents/{path}";
4✔
216
        string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
4✔
217
        if (!string.IsNullOrEmpty(response) &&
4!
218
            !response.Contains(@"""message"":""Not Found"""))
4✔
219
        {
3✔
220
            dynamic? jsonObj = JsonConvert.DeserializeObject(response);
3✔
221
            result = JsonConvert.DeserializeObject<GitHubFile>(jsonObj?.ToString());
3!
222

223
            //Decode the Base64 file contents result
224
            if (result != null && result.content != null)
3!
225
            {
3✔
226
                byte[]? valueBytes = System.Convert.FromBase64String(result.content);
3✔
227
                result.content = Encoding.UTF8.GetString(valueBytes);
3✔
228
            }
3✔
229
        }
3✔
230
        return result;
4✔
231
    }
4✔
232

233
    /// <summary>
234
    /// Get the branch policy for a repo/branch
235
    /// </summary>
236
    /// <param name="clientId"></param>
237
    /// <param name="clientSecret"></param>
238
    /// <param name="owner"></param>
239
    /// <param name="repo"></param>
240
    /// <param name="branch"></param>
241
    /// <returns></returns>
242
    public async static Task<BranchProtectionPolicy?> GetBranchProtectionPolicy(string? clientId, string? clientSecret,
243
        string owner, string repo, string branch)
244
    {
3✔
245
        BranchProtectionPolicy? result = null;
3✔
246
        if (clientId != null && clientSecret != null)
3!
247
        {
3✔
248
            string url = $"https://api.github.com/repos/{owner}/{repo}/branches/{branch}/protection";
3✔
249
            string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
3✔
250
            if (!string.IsNullOrEmpty(response) &&
3!
251
                !response.Contains(@"""message"":""Branch not protected"""))
3✔
252
            {
3✔
253
                dynamic? jsonObj = JsonConvert.DeserializeObject(response);
3✔
254
                result = JsonConvert.DeserializeObject<BranchProtectionPolicy>(jsonObj?.ToString());
3!
255
                result.RawJSON = jsonObj?.ToString();
3!
256
            }
3✔
257
        }
3✔
258
        return result;
3✔
259
    }
3✔
260

261
    /// <summary>
262
    /// Update a branch policy for a repo/branch. Lots of assumptions/simplifications are made today. This definition WILL change.
263
    /// </summary>
264
    /// <param name="clientId"></param>
265
    /// <param name="clientSecret"></param>
266
    /// <param name="owner"></param>
267
    /// <param name="repo"></param>
268
    /// <param name="branch"></param>
269
    /// <param name="requiredStatusCheck"></param>
270
    /// <returns></returns>
271
    public async static Task<bool> UpdateBranchProtectionPolicy(string? clientId, string? clientSecret, string owner, string repo,
272
        string branch, RequiredStatusCheckPut? requiredStatusCheck)
273
    {
1✔
274
        if (clientId != null && clientSecret != null)
1!
275
        {
1✔
276
            BranchProtectionPolicyPut body = new()
1✔
277
            {
1✔
278
                required_status_checks = requiredStatusCheck,
1✔
279
                required_pull_request_reviews = new()
1✔
280
                {
1✔
281
                    dismiss_stale_reviews = false,
1✔
282
                    required_approving_review_count = 0,
1✔
283
                    require_code_owner_reviews = false
1✔
284
                },
1✔
285
                restrictions = null,
1✔
286
                required_conversation_resolution = true,
1✔
287
                required_linear_history = false,
1✔
288
                enforce_admins = true,
1✔
289
                allow_force_pushes = false,
1✔
290
                allow_deletions = false
1✔
291
            };
1✔
292
            string json = JsonConvert.SerializeObject(body);
1✔
293

294
            StringContent content = new(json, Encoding.UTF8, "application/json");
1✔
295
            string url = $"https://api.github.com/repos/{owner}/{repo}/branches/{branch}/protection";
1✔
296
            string? response = await BaseApiAccess.PutGitHubMessage(url, clientId, clientSecret, content);
1✔
297
            if (string.IsNullOrEmpty(response))
1!
298
            {
×
299
                return false;
×
300
            }
301
        }
1✔
302
        return true;
1✔
303
    }
1✔
304

305
    /// <summary>
306
    /// Get the latest release for a repo
307
    /// </summary>
308
    /// <param name="clientId"></param>
309
    /// <param name="clientSecret"></param>
310
    /// <param name="owner"></param>
311
    /// <param name="repo"></param>
312
    /// <returns></returns>
313
    public async static Task<Release?> GetReleaseLatest(string? clientId, string? clientSecret,
314
        string owner, string repo)
315
    {
2✔
316
        Release? result = null;
2✔
317
        if (clientId != null && clientSecret != null)
2!
318
        {
2✔
319
            string url = $"https://api.github.com/repos/{owner}/{repo}/releases/latest";
2✔
320
            string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
2✔
321
            if (!string.IsNullOrEmpty(response))
2✔
322
            {
2✔
323
                dynamic? jsonObj = JsonConvert.DeserializeObject(response);
2✔
324
                result = JsonConvert.DeserializeObject<Release>(jsonObj?.ToString());
2!
325
                result.RawJSON = jsonObj?.ToString();
2!
326
            }
2✔
327
            //Check if the release is effectively empty - if so, mark it as null
328
            if (result != null && result.name == null)
2!
329
            {
1✔
330
                result = null;
1✔
331
            }
1✔
332
        }
2✔
333
        return result;
2✔
334
    }
2✔
335

336
    //IMPORTANT: Note that search has a rate limit of 30 requests per minute: https://docs.github.com/en/rest/reference/search#rate-limit
337
    public async static Task<SearchResult?> SearchFiles(string? clientId, string? clientSecret,
338
        string owner, string repo, string? extension = null, string? fileName = null, int counter = 0)
339
    {
3✔
340
        SearchResult? result = new();
3✔
341
        if (clientId != null && clientSecret != null)
3!
342
        {
3✔
343
            string url = "";
3✔
344
            if (extension != null)
3✔
345
            {
2✔
346
                //"https://api.github.com/search/code?q=extension:js+repo:vnation/NewsAggregator";
347
                url = $"https://api.github.com/search/code?q=extension:{extension}+repo:{owner}/{repo}";
2✔
348
            }
2✔
349
            else if (fileName != null)
1✔
350
            {
1✔
351
                //https://github.com/search?q=user%3Asamsmithnz+ProjectVersion.txt+filename%3AProjectVersion.txt&type=Repositories&ref=advsearch&l=&l=
352
                url = $"https://api.github.com/search/code?q=filename%3A{fileName}+repo:{owner}/{repo}";
1✔
353
            }
1✔
354
            if (!string.IsNullOrEmpty(url))
3✔
355
            {
3✔
356
                string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
3✔
357
                if (!string.IsNullOrEmpty(response))
3✔
358
                {
3✔
359
                    dynamic? jsonObj = JsonConvert.DeserializeObject(response);
3✔
360
                    result = JsonConvert.DeserializeObject<SearchResult>(jsonObj?.ToString());
3!
361
                }
3✔
362
                result.RawJSON = response;
3✔
363
            }
3✔
364
        }
3✔
365
        if (result?.incomplete_results == true && counter < 3)
3!
366
        {
×
367
            counter++;
×
368
            result = await SearchFiles(clientId, clientSecret, owner, repo, extension, fileName, counter);
×
369
        }
×
370

371
        return result;
3✔
372
    }
3✔
373

374
    public async static Task<string?> GetLastCommit(string? clientId, string? clientSecret,
375
        string owner, string repo)
376
    {
1✔
377
        string? result = null;
1✔
378
        if (clientId != null && clientSecret != null)
1!
379
        {
1✔
380
            //https://api.github.com/repos/torvalds/linux/commits?per_page=1
381
            string url = $"https://api.github.com/repos/{owner}/{repo}/commits?per_page=1";
1✔
382
            string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
1✔
383
            if (!string.IsNullOrEmpty(response))
1✔
384
            {
1✔
385
                dynamic? jsonObj = JsonConvert.DeserializeObject(response);
1✔
386
                Commit[] commits = JsonConvert.DeserializeObject<Commit[]>(jsonObj?.ToString());
1!
387
                if (commits != null && commits.Length > 0)
1!
388
                {
1✔
389
                    result = commits[0].sha;
1✔
390
                }
1✔
391
            }
1✔
392
        }
1✔
393
        return result;
1✔
394
    }
1✔
395

396
    public async static Task<List<PullRequest>> GetPullRequests(string? clientId, string? clientSecret,
397
        string owner, string repo)
398
    {
2✔
399
        List<PullRequest>? pullRequests = new();
2✔
400
        if (clientId != null && clientSecret != null)
2!
401
        {
2✔
402
            //https://docs.github.com/en/rest/pulls/pulls#list-pull-requests (only first 30)
403
            string url = $"https://api.github.com/repos/{owner}/{repo}/pulls?state=open";
2✔
404
            string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
2✔
405
            if (!string.IsNullOrEmpty(response))
2✔
406
            {
2✔
407
                dynamic? jsonObj = JsonConvert.DeserializeObject(response);
2✔
408
                PR[] prs = JsonConvert.DeserializeObject<PR[]>(jsonObj?.ToString());
2!
409
                if (prs != null && prs.Length > 0)
2!
410
                {
2✔
411
                    foreach (PR pr in prs)
30✔
412
                    {
12✔
413
                        PullRequest newPullRequest = new()
12!
414
                        {
12✔
415
                            Number = pr.number,
12✔
416
                            Title = pr.title,
12✔
417
                            State = pr.state,
12✔
418
                            LoginUser = pr?.user?.login
12✔
419
                        };
12✔
420
                        if (pr != null && pr.updated_at != null)
12!
421
                        {
12✔
422
                            newPullRequest.LastUpdated = DateTime.Parse(pr.updated_at);
12✔
423
                        }
12✔
424
                        //if (pr.auto_merge == null)
425
                        //{
426
                        //    newPullRequest.AutoMergeEnabled = false;
427
                        //}
428
                        //else
429
                        //{
430
                        //    newPullRequest.AutoMergeEnabled = bool.Parse(pr.auto_merge);
431
                        //}
432
                        if (pr != null && pr.labels != null)
12!
433
                        {
12✔
434
                            foreach (Label item in pr.labels)
80✔
435
                            {
22✔
436
                                if (item != null && item.name != null)
22!
437
                                {
22✔
438
                                    newPullRequest.Labels.Add(item.name);
22✔
439
                                    if (item.name == "dependencies")
22✔
440
                                    {
10✔
441
                                        newPullRequest.IsDependabotPR = true;
10✔
442
                                    }
10✔
443
                                }
22✔
444
                            }
22✔
445
                        }
12✔
446
                        pullRequests.Add(newPullRequest);
12✔
447
                    }
12✔
448
                }
2✔
449
            }
2✔
450
        }
2✔
451
        return pullRequests;
2✔
452
    }
2✔
453

454
    public async static Task<List<PRReview>> GetPullRequestReview(string? clientId, string? clientSecret,
455
        string owner, string repo, string pullRequestNumber)
456
    {
2✔
457
        List<PRReview> prReview = new();
2✔
458
        if (clientId != null && clientSecret != null)
2!
459
        {
2✔
460
            //https://docs.github.com/en/rest/pulls/reviews#submit-a-pull-request-review
461
            string url = $"https://api.github.com/repos/{owner}/{repo}/pulls/{pullRequestNumber}/reviews";
2✔
462
            string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
2✔
463
            if (!string.IsNullOrEmpty(response))
2✔
464
            {
2✔
465
                dynamic? jsonObj = JsonConvert.DeserializeObject(response);
2✔
466
                prReview = JsonConvert.DeserializeObject<List<PRReview>>(jsonObj?.ToString());
2!
467
            }
2✔
468
        }
2✔
469

470
        return prReview;
2✔
471
    }
2✔
472

473
    public async static Task<Dictionary<string, int>> GetRepoLanguages(string? clientId, string? clientSecret,
474
        string owner, string repo)
475
    {
2✔
476
        Dictionary<string, int> languages = new();
2✔
477
        if (clientId != null && clientSecret != null)
2!
478
        {
2✔
479
            //https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#list-repository-languages
480
            string url = $"https://api.github.com/repos/{owner}/{repo}/languages";
2✔
481
            string? response = await BaseApiAccess.GetGitHubMessage(url, clientId, clientSecret, false);
2✔
482
            if (!string.IsNullOrEmpty(response))
2✔
483
            {
2✔
484
                dynamic? jsonObj = JsonConvert.DeserializeObject(response);
2✔
485
                languages = JsonConvert.DeserializeObject<Dictionary<string, int>>(jsonObj?.ToString());
2!
486
            }
2✔
487
        }
2✔
488

489
        return languages;
2✔
490
    }
2✔
491

492
    //Approve Pull Request
493
    public async static Task<bool> ApprovePullRequests(string? clientId, string? clientSecret,
494
        string owner, string repo, string approver)
495
    {
1✔
496
        bool result = false;
1✔
497
        //Get the pull request details
498
        List<PullRequest> pullRequests = await GetPullRequests(clientId, clientSecret, owner, repo);
1✔
499

500
        foreach (PullRequest pr in pullRequests)
15✔
501
        {
6✔
502
            if (pr.LoginUser != approver)
6✔
503
            {
5✔
504
                //Approve the pull request (if the approver is not the author)
505
                //https://api.github.com/repos/OWNER/REPO/pulls/PULL_NUMBER/reviews
506
                if (clientId != null && clientSecret != null)
5!
507
                {
5✔
508
                    var body = new
5✔
509
                    {
5✔
510
                        @event = "APPROVE" //Note that event is a reserved word and therefore needs the @prefix
5✔
511
                    };
5✔
512
                    //https://docs.github.com/en/rest/pulls/reviews?apiVersion=2022-11-28#create-a-review-for-a-pull-request
513
                    string url = $"https://api.github.com/repos/{owner}/{repo}/pulls/{pr.Number}/reviews";
5✔
514
                    StringContent content = new(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
5✔
515
                    string? response = await BaseApiAccess.PostGitHubMessage(url, clientId, clientSecret, content, false);
5✔
516
                    if (!string.IsNullOrEmpty(response))
5✔
517
                    {
5✔
518
                        dynamic? jsonObj = JsonConvert.DeserializeObject(response);
5✔
519
                        PRReview pullRequestReview = JsonConvert.DeserializeObject<PRReview>(jsonObj?.ToString());
5!
520
                        if (pullRequestReview.submitted_at != null)
5!
521
                        {
5✔
522
                            result = true;
5✔
523
                        }
5✔
524
                        else
525
                        {
×
526
                            return false;
×
527
                        }
528
                    }
5✔
529
                }
5✔
530
            }
5✔
531
        }
6✔
532

533
        return result;
1✔
534
    }
1✔
535

536
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc