Skip to content

Commit 435411d

Browse files
authored
Merge pull request #423 from FlowCI/feature/1580
Feature/1580
2 parents 08d4ddf + ea1ccbc commit 435411d

File tree

14 files changed

+316
-38
lines changed

14 files changed

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

4545
@Override
46-
public void writeCommitStatus(GitCommitStatus commit, Secret secret) {
46+
public void writeCommitStatus(GitCommitStatus commit, GitConfig config) {
47+
var secret = config.getSecretObj();
48+
4749
if (!(secret instanceof TokenSecret)) {
48-
throw new ArgumentException("Token secret is required");
50+
throw new ArgumentException("Token secret is required Github");
4951
}
5052

5153
var tokenSecret = (TokenSecret) secret;

core/src/main/java/com/flowci/core/git/controller/GitConfigController.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import com.flowci.core.auth.annotation.Action;
44
import com.flowci.core.common.domain.GitSource;
55
import com.flowci.core.git.domain.GitConfig;
6-
import com.flowci.core.git.service.GitService;
6+
import com.flowci.core.git.service.GitConfigService;
7+
import com.flowci.exception.ArgumentException;
78
import lombok.extern.log4j.Log4j2;
89
import org.springframework.beans.factory.annotation.Autowired;
910
import org.springframework.web.bind.annotation.*;
@@ -16,29 +17,33 @@
1617
public class GitConfigController {
1718

1819
@Autowired
19-
private GitService gitService;
20+
private GitConfigService gitConfigService;
2021

2122
@Action(GitActions.LIST)
2223
@GetMapping
2324
public List<GitConfig> list() {
24-
return gitService.list();
25+
return gitConfigService.list();
2526
}
2627

2728
@Action(GitActions.GET)
2829
@GetMapping("/{source}")
2930
public GitConfig get(@PathVariable String source) {
30-
return gitService.get(GitSource.valueOf(source.toUpperCase()));
31+
return gitConfigService.get(GitSource.valueOf(source.toUpperCase()));
3132
}
3233

3334
@Action(GitActions.SAVE)
3435
@PostMapping()
3536
public GitConfig save(@RequestBody Request.SaveOptions options) {
36-
return gitService.save(options.toGitConfig());
37+
if (options.getSource() == GitSource.GERRIT && options.getHost() == null) {
38+
throw new ArgumentException("Host address is required for Gerrit");
39+
}
40+
41+
return gitConfigService.save(options.toGitConfig());
3742
}
3843

3944
@Action(GitActions.DELETE)
4045
@DeleteMapping("/{source}")
4146
public void delete(@PathVariable String source) {
42-
gitService.delete(GitSource.valueOf(source.toUpperCase()));
47+
gitConfigService.delete(GitSource.valueOf(source.toUpperCase()));
4348
}
4449
}

core/src/main/java/com/flowci/core/git/controller/Request.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import com.flowci.core.common.domain.GitSource;
44
import com.flowci.core.git.domain.GitConfig;
5+
import com.flowci.core.git.domain.GitConfigWithHost;
6+
import com.flowci.util.StringHelper;
57
import lombok.Getter;
68
import lombok.Setter;
79

@@ -17,10 +19,16 @@ public static class SaveOptions {
1719
@NotNull
1820
private GitSource source;
1921

22+
private String host;
23+
2024
@NotEmpty
2125
private String secret;
2226

2327
public GitConfig toGitConfig() {
28+
if (StringHelper.hasValue(host)) {
29+
return new GitConfigWithHost(source, secret, host);
30+
}
31+
2432
return new GitConfig(source, secret);
2533
}
2634
}

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: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.flowci.core.git.domain;
2+
3+
import com.flowci.core.common.domain.GitSource;
4+
import lombok.Getter;
5+
import lombok.NoArgsConstructor;
6+
import lombok.Setter;
7+
import org.springframework.data.mongodb.core.mapping.Document;
8+
9+
@Setter
10+
@Getter
11+
@Document(collection = "git_config")
12+
@NoArgsConstructor
13+
public class GitConfigWithHost extends GitConfig {
14+
15+
private String host;
16+
17+
public GitConfigWithHost(GitSource source, String secret, String host) {
18+
super(source, secret);
19+
this.host = host;
20+
}
21+
}

core/src/main/java/com/flowci/core/git/service/GitService.java renamed to core/src/main/java/com/flowci/core/git/service/GitConfigService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import java.util.List;
77

8-
public interface GitService {
8+
public interface GitConfigService {
99

1010
List<GitConfig> list();
1111

0 commit comments

Comments
 (0)