Skip to content

Commit dfa47a1

Browse files
committed
impl gerrit api client
1 parent 08d4ddf commit dfa47a1

File tree

10 files changed

+206
-11
lines changed

10 files changed

+206
-11
lines changed

core/src/main/java/com/flowci/core/common/config/MongoConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import com.flowci.core.common.mongo.VariableMapConverter;
2525
import com.flowci.core.config.domain.SmtpConfig;
2626
import com.flowci.core.config.domain.TextConfig;
27+
import com.flowci.core.git.domain.GitConfig;
28+
import com.flowci.core.git.domain.GitConfigWithHost;
2729
import com.flowci.core.job.domain.JobItem;
2830
import com.flowci.core.secret.domain.*;
2931
import com.flowci.core.trigger.domain.EmailTrigger;
@@ -111,6 +113,8 @@ public MongoMappingContext mongoMappingContext(MongoCustomConversions customConv
111113
context.addEntity(EmailTrigger.class);
112114
context.addEntity(WebhookTrigger.class);
113115

116+
context.addEntity(GitConfigWithHost.class);
117+
114118
return context;
115119
}
116120

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package com.flowci.core.git.client;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import com.fasterxml.jackson.core.JsonProcessingException;
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import com.flowci.core.git.domain.GitCommitStatus;
7+
import com.flowci.core.git.domain.GitConfig;
8+
import com.flowci.core.git.domain.GitConfigWithHost;
9+
import com.flowci.core.git.util.CommitHelper;
10+
import com.flowci.core.secret.domain.AuthSecret;
11+
import com.flowci.exception.ArgumentException;
12+
import com.flowci.exception.CIException;
13+
import com.flowci.exception.NotFoundException;
14+
import com.flowci.util.StringHelper;
15+
import lombok.AllArgsConstructor;
16+
import lombok.NoArgsConstructor;
17+
import lombok.extern.log4j.Log4j2;
18+
import org.springframework.http.HttpStatus;
19+
20+
import java.net.URI;
21+
import java.net.http.HttpClient;
22+
import java.net.http.HttpRequest;
23+
import java.net.http.HttpResponse;
24+
25+
@Log4j2
26+
public class GerritAPIClient implements GitAPIClient {
27+
28+
private final static String SetReviewAPI = "%s/repos/a/changes/%s/revisions/%s/review";
29+
30+
private final HttpClient httpClient;
31+
32+
private final ObjectMapper objectMapper;
33+
34+
public GerritAPIClient(HttpClient httpClient, ObjectMapper objectMapper) {
35+
this.httpClient = httpClient;
36+
this.objectMapper = objectMapper;
37+
}
38+
39+
/**
40+
* Write commit status on change only
41+
*/
42+
@Override
43+
public void writeCommitStatus(GitCommitStatus commit, GitConfig config) {
44+
if (!(config instanceof GitConfigWithHost)) {
45+
throw new ArgumentException("GitConfigWithHost is required for Gerrit");
46+
}
47+
48+
var secret = config.getSecretObj();
49+
if (!(secret instanceof AuthSecret)) {
50+
throw new ArgumentException("AuthSecret is required for Gerrit");
51+
}
52+
53+
var changeId = CommitHelper.getChangeId(commit);
54+
if (changeId.isEmpty()) {
55+
throw new NotFoundException("Change-Id not found from commit message");
56+
}
57+
58+
try {
59+
var gitConfig = (GitConfigWithHost) config;
60+
var url = String.format(SetReviewAPI, gitConfig.getHost(), changeId.get(), commit.getId());
61+
var request = getRequestBuilder(url, (AuthSecret) secret)
62+
.POST(HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(getBodyObj(commit))))
63+
.build();
64+
65+
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
66+
.thenAccept(r -> {
67+
log.info("Update commit status on {} is {}", commit.getUrl(), r.statusCode());
68+
if (r.statusCode() != HttpStatus.OK.value()) {
69+
log.debug(r.body());
70+
}
71+
});
72+
73+
} catch (JsonProcessingException e) {
74+
throw new CIException("Unable to convert gerrit commit body to json: " + e.getMessage());
75+
}
76+
}
77+
78+
private HttpRequest.Builder getRequestBuilder(String url, AuthSecret secret) {
79+
var str = secret.getUsername() + ":" + secret.getPassword();
80+
return HttpRequest.newBuilder(URI.create(url))
81+
.setHeader("Authorization", "Basic " + StringHelper.toBase64(str));
82+
}
83+
84+
private SetReviewBody getBodyObj(GitCommitStatus c) {
85+
var obj = new SetReviewBody();
86+
obj.tag = "flow.ci";
87+
obj.message = c.getDesc() + " - " + c.getTargetUrl();
88+
obj.labels = new Labels(-1);
89+
90+
if (c.getStatus().contains("success")) {
91+
obj.labels.codeReview = 1;
92+
}
93+
94+
return obj;
95+
}
96+
97+
private static class SetReviewBody {
98+
99+
public String tag;
100+
101+
public String message;
102+
103+
public Labels labels;
104+
}
105+
106+
@AllArgsConstructor
107+
@NoArgsConstructor
108+
private static class Labels {
109+
110+
@JsonProperty("Code-Review")
111+
public int codeReview;
112+
}
113+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package com.flowci.core.git.client;
22

33
import com.flowci.core.git.domain.GitCommitStatus;
4-
import com.flowci.core.secret.domain.Secret;
4+
import com.flowci.core.git.domain.GitConfig;
55

66
public interface GitAPIClient {
77

8-
void writeCommitStatus(GitCommitStatus commit, Secret secret);
8+
void writeCommitStatus(GitCommitStatus commit, GitConfig config);
99
}

core/src/main/java/com/flowci/core/git/client/GithubAPIClient.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.fasterxml.jackson.databind.ObjectMapper;
66
import com.flowci.core.git.domain.GitCommit;
77
import com.flowci.core.git.domain.GitCommitStatus;
8+
import com.flowci.core.git.domain.GitConfig;
89
import com.flowci.core.git.domain.GitRepo;
910
import com.flowci.core.secret.domain.Secret;
1011
import com.flowci.core.secret.domain.TokenSecret;
@@ -43,9 +44,11 @@ public GithubAPIClient(HttpClient httpClient, ObjectMapper objectMapper) {
4344
}
4445

4546
@Override
46-
public void writeCommitStatus(GitCommitStatus commit, Secret secret) {
47+
public void writeCommitStatus(GitCommitStatus commit, GitConfig config) {
48+
var secret = config.getSecretObj();
49+
4750
if (!(secret instanceof TokenSecret)) {
48-
throw new ArgumentException("Token secret is required");
51+
throw new ArgumentException("Token secret is required Github");
4952
}
5053

5154
var tokenSecret = (TokenSecret) secret;

core/src/main/java/com/flowci/core/git/domain/GitCommitStatus.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
@Setter
88
public class GitCommitStatus extends GitCommit {
99

10-
private String status;
10+
private String status; // lower case from job status
1111

1212
private String targetUrl;
1313

core/src/main/java/com/flowci/core/git/domain/GitConfig.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,28 @@
22

33
import com.flowci.core.common.domain.GitSource;
44
import com.flowci.core.common.domain.Mongoable;
5+
import com.flowci.core.secret.domain.Secret;
56
import lombok.Getter;
67
import lombok.NoArgsConstructor;
78
import lombok.Setter;
9+
import org.springframework.data.annotation.Transient;
810
import org.springframework.data.mongodb.core.index.Indexed;
11+
import org.springframework.data.mongodb.core.mapping.Document;
912

1013
@Getter
1114
@Setter
1215
@NoArgsConstructor
16+
@Document(collection = "git_config")
1317
public class GitConfig extends Mongoable {
1418

1519
@Indexed(unique = true)
1620
private GitSource source;
1721

1822
private String secret;
1923

24+
@Transient
25+
private Secret secretObj;
26+
2027
public GitConfig(GitSource source, String secret) {
2128
this.source = source;
2229
this.secret = secret;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.flowci.core.git.domain;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
import org.springframework.data.mongodb.core.mapping.Document;
6+
7+
@Setter
8+
@Getter
9+
@Document(collection = "git_config")
10+
public class GitConfigWithHost extends GitConfig {
11+
12+
private String host;
13+
}

core/src/main/java/com/flowci/core/git/service/GitServiceImpl.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ public void onJobFinishEvent(JobFinishedEvent event) {
8787
}
8888

8989
try {
90-
var handler = getHandler(GitSource.valueOf(gitSourceStr));
90+
GitSource source = GitSource.valueOf(gitSourceStr);
91+
var handler = getHandler(source);
9192

9293
var commit = new GitCommitStatus();
9394
commit.setId(JobContextHelper.getCommitId(job));
@@ -96,7 +97,7 @@ public void onJobFinishEvent(JobFinishedEvent event) {
9697
commit.setStatus(JobContextHelper.getStatus(job).name().toLowerCase());
9798
commit.setDesc(String.format("build %s from flow.ci", commit.getStatus()));
9899

99-
handler.writeCommit(commit);
100+
handler.writeCommit(commit, get(source));
100101
} catch (Throwable e) {
101102
log.warn(e.getMessage());
102103
}
@@ -114,7 +115,7 @@ private interface OperationHandler {
114115

115116
GitConfig save(GitConfig config);
116117

117-
void writeCommit(GitCommitStatus commit);
118+
void writeCommit(GitCommitStatus commit, GitConfig config);
118119
}
119120

120121
private class GitHubOperationHandler implements OperationHandler {
@@ -142,7 +143,7 @@ public GitConfig save(GitConfig config) {
142143
}
143144

144145
@Override
145-
public void writeCommit(GitCommitStatus commit) {
146+
public void writeCommit(GitCommitStatus commit, GitConfig config) {
146147
var c = get(GitSource.GITHUB);
147148
var event = eventManager.publish(new GetSecretEvent(GitServiceImpl.this, c.getSecret()));
148149
Secret secret = event.getFetched();
@@ -151,8 +152,8 @@ public void writeCommit(GitCommitStatus commit) {
151152
throw new ArgumentException("Token secret is required");
152153
}
153154

154-
TokenSecret tokenSecret = (TokenSecret) secret;
155-
client.writeCommitStatus(commit, tokenSecret);
155+
config.setSecretObj(secret);
156+
client.writeCommitStatus(commit, config);
156157
}
157158
}
158159
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.flowci.core.git.util;
2+
3+
import com.flowci.core.git.domain.GitCommit;
4+
import com.flowci.util.StringHelper;
5+
6+
import java.util.Optional;
7+
8+
public abstract class CommitHelper {
9+
10+
private final static String ChangeIdStr = "Change-Id:";
11+
12+
public static Optional<String> getChangeId(GitCommit commit) {
13+
String message = commit.getMessage();
14+
if (!StringHelper.hasValue(message)) {
15+
return Optional.empty();
16+
}
17+
18+
int i = message.lastIndexOf(ChangeIdStr);
19+
if (i == -1) {
20+
return Optional.empty();
21+
}
22+
23+
int end = message.indexOf('\n', i);
24+
if (end == -1) {
25+
return Optional.of(message.substring(i + ChangeIdStr.length() + 1));
26+
}
27+
28+
return Optional.of(message.substring(i + ChangeIdStr.length() + 1, end));
29+
}
30+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.flowci.core.test.git;
2+
3+
import com.flowci.core.git.domain.GitCommit;
4+
import com.flowci.core.git.util.CommitHelper;
5+
import org.junit.Test;
6+
import org.junit.Assert;;
7+
8+
public class CommitHelperTest {
9+
10+
@Test
11+
public void should_get_change_id_from_commit_message() {
12+
var msg = "try task 1 patchset\n" +
13+
"\n" +
14+
"Change-Id: I9a55b4d3fe33d2efae107a38fc2744bfc95bfea9" +
15+
"\n";
16+
17+
var commit = new GitCommit();
18+
commit.setMessage(msg);
19+
20+
var changeId = CommitHelper.getChangeId(commit);
21+
Assert.assertTrue(changeId.isPresent());
22+
Assert.assertEquals("I9a55b4d3fe33d2efae107a38fc2744bfc95bfea9", changeId.get());
23+
}
24+
}

0 commit comments

Comments
 (0)