Skip to content

Commit

Permalink
Merge pull request #1504 from gsmet/workflow-run-approve
Browse files Browse the repository at this point in the history
Implement workflow run approval
  • Loading branch information
bitwiseman committed Aug 18, 2022
2 parents e5fb0cd + de1345b commit f540664
Show file tree
Hide file tree
Showing 12 changed files with 1,900 additions and 2 deletions.
10 changes: 10 additions & 0 deletions src/main/java/org/kohsuke/github/GHWorkflowRun.java
Expand Up @@ -299,6 +299,16 @@ public void rerun() throws IOException {
root().createRequest().method("POST").withUrlPath(getApiRoute(), "rerun").send();
}

/**
* Approve the workflow run.
*
* @throws IOException
* the io exception
*/
public void approve() throws IOException {
root().createRequest().method("POST").withUrlPath(getApiRoute(), "approve").send();
}

/**
* Lists the artifacts attached to this workflow run.
*
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/org/kohsuke/github/GHWorkflowRunQueryBuilder.java
@@ -1,5 +1,6 @@
package org.kohsuke.github;

import org.kohsuke.github.GHWorkflowRun.Conclusion;
import org.kohsuke.github.GHWorkflowRun.Status;

/**
Expand Down Expand Up @@ -88,6 +89,20 @@ public GHWorkflowRunQueryBuilder status(Status status) {
return this;
}

/**
* Conclusion workflow run query builder.
* <p>
* The GitHub API is also using the status field to search by conclusion.
*
* @param conclusion
* the conclusion
* @return the gh workflow run query builder
*/
public GHWorkflowRunQueryBuilder conclusion(Conclusion conclusion) {
req.with("status", conclusion.toString());
return this;
}

@Override
public PagedIterable<GHWorkflowRun> list() {
return new GHWorkflowRunsIterable(repo, req.withUrlPath(repo.getApiTailUrl("actions/runs")));
Expand Down
69 changes: 67 additions & 2 deletions src/test/java/org/kohsuke/github/GHWorkflowRunTest.java
Expand Up @@ -3,6 +3,7 @@
import org.awaitility.Awaitility;
import org.junit.Before;
import org.junit.Test;
import org.kohsuke.github.GHPullRequestQueryBuilder.Sort;
import org.kohsuke.github.GHWorkflowJob.Step;
import org.kohsuke.github.GHWorkflowRun.Conclusion;
import org.kohsuke.github.GHWorkflowRun.Status;
Expand Down Expand Up @@ -362,18 +363,57 @@ public void testJobs() throws IOException {
assertThat(allJobs.size(), greaterThanOrEqualTo(2));
}

private void await(Function<GHRepository, Boolean> condition) throws IOException {
@Test
public void testApproval() throws IOException {
List<GHPullRequest> pullRequests = repo.queryPullRequests()
.base(MAIN_BRANCH)
.sort(Sort.CREATED)
.direction(GHDirection.DESC)
.state(GHIssueState.OPEN)
.list()
.toList();

assertThat(pullRequests.size(), greaterThanOrEqualTo(1));
GHPullRequest pullRequest = pullRequests.get(0);

await("Waiting for workflow run to be pending",
(nonRecordingRepo) -> getWorkflowRun(nonRecordingRepo,
FAST_WORKFLOW_NAME,
MAIN_BRANCH,
Conclusion.ACTION_REQUIRED).isPresent());

GHWorkflowRun workflowRun = getWorkflowRun(FAST_WORKFLOW_NAME, MAIN_BRANCH, Conclusion.ACTION_REQUIRED)
.orElseThrow(() -> new IllegalStateException("We must have a valid workflow run starting from here"));

workflowRun.approve();

await("Waiting for workflow run to be approved",
(nonRecordingRepo) -> getWorkflowRun(nonRecordingRepo,
FAST_WORKFLOW_NAME,
pullRequest.getHead().getRef(),
Conclusion.SUCCESS).isPresent());

workflowRun = repo.getWorkflowRun(workflowRun.getId());

assertThat(workflowRun.getConclusion(), is(Conclusion.SUCCESS));
}

private void await(String alias, Function<GHRepository, Boolean> condition) throws IOException {
if (!mockGitHub.isUseProxy()) {
return;
}

GHRepository nonRecordingRepo = getNonRecordingGitHub().getRepository(REPO_NAME);

Awaitility.await().pollInterval(Duration.ofSeconds(5)).atMost(Duration.ofSeconds(60)).until(() -> {
Awaitility.await(alias).pollInterval(Duration.ofSeconds(5)).atMost(Duration.ofSeconds(60)).until(() -> {
return condition.apply(nonRecordingRepo);
});
}

private void await(Function<GHRepository, Boolean> condition) throws IOException {
await(null, condition);
}

private long getLatestPreexistingWorkflowRunId() {
return repo.queryWorkflowRuns().list().withPageSize(1).iterator().next().getId();
}
Expand Down Expand Up @@ -407,6 +447,31 @@ private Optional<GHWorkflowRun> getWorkflowRun(String workflowName,
return getWorkflowRun(this.repo, workflowName, branch, status, latestPreexistingWorkflowRunId);
}

private static Optional<GHWorkflowRun> getWorkflowRun(GHRepository repository,
String workflowName,
String branch,
Conclusion conclusion) {
List<GHWorkflowRun> workflowRuns = repository.queryWorkflowRuns()
.branch(branch)
.conclusion(conclusion)
.event(GHEvent.PULL_REQUEST)
.list()
.withPageSize(20)
.iterator()
.nextPage();

for (GHWorkflowRun workflowRun : workflowRuns) {
if (workflowRun.getName().equals(workflowName)) {
return Optional.of(workflowRun);
}
}
return Optional.empty();
}

private Optional<GHWorkflowRun> getWorkflowRun(String workflowName, String branch, Conclusion conclusion) {
return getWorkflowRun(this.repo, workflowName, branch, conclusion);
}

private static Status getWorkflowRunStatus(GHRepository repository, long workflowRunId) {
try {
return repository.getWorkflowRun(workflowRunId).getStatus();
Expand Down
@@ -0,0 +1,140 @@
{
"id": 348674220,
"node_id": "MDEwOlJlcG9zaXRvcnkzNDg2NzQyMjA=",
"name": "GHWorkflowRunTest",
"full_name": "hub4j-test-org/GHWorkflowRunTest",
"private": false,
"owner": {
"login": "hub4j-test-org",
"id": 7544739,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
"avatar_url": "https://avatars.githubusercontent.com/u/7544739?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/hub4j-test-org",
"html_url": "https://github.com/hub4j-test-org",
"followers_url": "https://api.github.com/users/hub4j-test-org/followers",
"following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
"gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
"starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
"organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
"repos_url": "https://api.github.com/users/hub4j-test-org/repos",
"events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
"received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
"type": "Organization",
"site_admin": false
},
"html_url": "https://github.com/hub4j-test-org/GHWorkflowRunTest",
"description": "Repository used by GHWorkflowRunTest",
"fork": false,
"url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest",
"forks_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/forks",
"keys_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/teams",
"hooks_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/hooks",
"issue_events_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/issues/events{/number}",
"events_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/events",
"assignees_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/assignees{/user}",
"branches_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/branches{/branch}",
"tags_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/tags",
"blobs_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/statuses/{sha}",
"languages_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/languages",
"stargazers_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/stargazers",
"contributors_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/contributors",
"subscribers_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/subscribers",
"subscription_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/subscription",
"commits_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/contents/{+path}",
"compare_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/merges",
"archive_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/downloads",
"issues_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/issues{/number}",
"pulls_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/pulls{/number}",
"milestones_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/milestones{/number}",
"notifications_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/labels{/name}",
"releases_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/releases{/id}",
"deployments_url": "https://api.github.com/repos/hub4j-test-org/GHWorkflowRunTest/deployments",
"created_at": "2021-03-17T10:50:49Z",
"updated_at": "2021-04-05T12:08:00Z",
"pushed_at": "2022-08-17T10:55:33Z",
"git_url": "git://github.com/hub4j-test-org/GHWorkflowRunTest.git",
"ssh_url": "git@github.com:hub4j-test-org/GHWorkflowRunTest.git",
"clone_url": "https://github.com/hub4j-test-org/GHWorkflowRunTest.git",
"svn_url": "https://github.com/hub4j-test-org/GHWorkflowRunTest",
"homepage": null,
"size": 7,
"stargazers_count": 0,
"watchers_count": 0,
"language": null,
"has_issues": true,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": false,
"forks_count": 1,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 8,
"license": null,
"allow_forking": true,
"is_template": false,
"web_commit_signoff_required": false,
"topics": [],
"visibility": "public",
"forks": 1,
"open_issues": 8,
"watchers": 0,
"default_branch": "main",
"permissions": {
"admin": true,
"maintain": true,
"push": true,
"triage": true,
"pull": true
},
"temp_clone_token": "",
"allow_squash_merge": true,
"allow_merge_commit": true,
"allow_rebase_merge": true,
"allow_auto_merge": false,
"delete_branch_on_merge": false,
"allow_update_branch": false,
"use_squash_pr_title_as_default": false,
"squash_merge_commit_message": "COMMIT_MESSAGES",
"squash_merge_commit_title": "COMMIT_OR_PR_TITLE",
"merge_commit_message": "PR_TITLE",
"merge_commit_title": "MERGE_MESSAGE",
"organization": {
"login": "hub4j-test-org",
"id": 7544739,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
"avatar_url": "https://avatars.githubusercontent.com/u/7544739?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/hub4j-test-org",
"html_url": "https://github.com/hub4j-test-org",
"followers_url": "https://api.github.com/users/hub4j-test-org/followers",
"following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
"gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
"starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
"organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
"repos_url": "https://api.github.com/users/hub4j-test-org/repos",
"events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
"received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
"type": "Organization",
"site_admin": false
},
"network_count": 1,
"subscribers_count": 10
}

0 comments on commit f540664

Please sign in to comment.