Skip to content

Commit d2bfee1

Browse files
feat: add Code Governance Git Provider APIs
Enterprise features for creating PRs from LLM-generated code: - validateGitProvider() - Validate credentials before saving - configureGitProvider() - Configure GitHub, GitLab, or Bitbucket - listGitProviders() - List configured providers - deleteGitProvider() - Remove a provider - createPR() - Create PR from generated code with audit trail - listPRs() - List PRs with filtering - getPR() - Get PR details - syncPRStatus() - Sync status from Git provider Supported Git Providers: - GitHub (Cloud and Enterprise Server) - GitLab (Cloud and Self-Managed) - Bitbucket (Cloud and Server/Data Center) Bump version to 1.4.0
1 parent 43604f4 commit d2bfee1

18 files changed

Lines changed: 1654 additions & 1 deletion

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@ All notable changes to the AxonFlow Java SDK will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.4.0] - 2025-12-29
9+
10+
### Added
11+
12+
- **Code Governance Git Provider APIs** (Enterprise): Create PRs from LLM-generated code
13+
- `validateGitProvider()` - Validate credentials before saving
14+
- `configureGitProvider()` - Configure GitHub, GitLab, or Bitbucket
15+
- `listGitProviders()` - List configured providers
16+
- `deleteGitProvider()` - Remove a provider
17+
- `createPR()` - Create PR from generated code with audit trail
18+
- `listPRs()` - List PRs with filtering
19+
- `getPR()` - Get PR details
20+
- `syncPRStatus()` - Sync status from Git provider
21+
22+
- **New Types**: `GitProviderType`, `FileAction`, `CodeFile`, `CreatePRRequest`, `CreatePRResponse`, `PRRecord`, `ListPRsOptions`, `ListPRsResponse`
23+
24+
- **Supported Git Providers**:
25+
- GitHub (Cloud and Enterprise Server)
26+
- GitLab (Cloud and Self-Managed)
27+
- Bitbucket (Cloud and Server/Data Center)
28+
29+
---
30+
831
## [1.3.1] - 2025-12-29
932

1033
### Fixed

pom.xml

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

77
<groupId>com.getaxonflow</groupId>
88
<artifactId>axonflow-sdk</artifactId>
9-
<version>1.3.1</version>
9+
<version>1.4.0</version>
1010
<packaging>jar</packaging>
1111

1212
<name>AxonFlow Java SDK</name>

src/main/java/com/getaxonflow/sdk/AxonFlow.java

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.getaxonflow.sdk.exceptions.*;
1919
import com.getaxonflow.sdk.types.*;
20+
import com.getaxonflow.sdk.types.codegovernance.*;
2021
import com.getaxonflow.sdk.types.policies.PolicyTypes.*;
2122
import com.getaxonflow.sdk.util.*;
2223
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -1343,6 +1344,220 @@ private String extractErrorMessage(String body, String defaultMessage) {
13431344
return defaultMessage;
13441345
}
13451346

1347+
// ========================================================================
1348+
// Code Governance - Git Provider APIs (Enterprise)
1349+
// ========================================================================
1350+
1351+
/**
1352+
* Validates Git provider credentials without saving them.
1353+
*
1354+
* @param request the validation request with provider type and credentials
1355+
* @return validation result
1356+
* @throws IOException if the request fails
1357+
*/
1358+
public ValidateGitProviderResponse validateGitProvider(ValidateGitProviderRequest request) throws IOException {
1359+
logger.debug("Validating Git provider: {}", request.getType());
1360+
1361+
String json = objectMapper.writeValueAsString(request);
1362+
RequestBody body = RequestBody.create(json, JSON);
1363+
1364+
Request httpRequest = new Request.Builder()
1365+
.url(config.getAgentUrl() + "/api/v1/code-governance/git-providers/validate")
1366+
.post(body)
1367+
.build();
1368+
1369+
addAuthHeaders(httpRequest.newBuilder());
1370+
1371+
Request.Builder builder = httpRequest.newBuilder();
1372+
addAuthHeaders(builder);
1373+
1374+
try (Response response = httpClient.newCall(builder.build()).execute()) {
1375+
return parseResponse(response, ValidateGitProviderResponse.class);
1376+
}
1377+
}
1378+
1379+
/**
1380+
* Configures a Git provider for code governance.
1381+
*
1382+
* @param request the configuration request with provider type and credentials
1383+
* @return configuration result
1384+
* @throws IOException if the request fails
1385+
*/
1386+
public ConfigureGitProviderResponse configureGitProvider(ConfigureGitProviderRequest request) throws IOException {
1387+
logger.debug("Configuring Git provider: {}", request.getType());
1388+
1389+
String json = objectMapper.writeValueAsString(request);
1390+
RequestBody body = RequestBody.create(json, JSON);
1391+
1392+
Request.Builder builder = new Request.Builder()
1393+
.url(config.getAgentUrl() + "/api/v1/code-governance/git-providers")
1394+
.post(body);
1395+
1396+
addAuthHeaders(builder);
1397+
1398+
try (Response response = httpClient.newCall(builder.build()).execute()) {
1399+
return parseResponse(response, ConfigureGitProviderResponse.class);
1400+
}
1401+
}
1402+
1403+
/**
1404+
* Lists configured Git providers.
1405+
*
1406+
* @return list of configured providers
1407+
* @throws IOException if the request fails
1408+
*/
1409+
public ListGitProvidersResponse listGitProviders() throws IOException {
1410+
logger.debug("Listing Git providers");
1411+
1412+
Request.Builder builder = new Request.Builder()
1413+
.url(config.getAgentUrl() + "/api/v1/code-governance/git-providers")
1414+
.get();
1415+
1416+
addAuthHeaders(builder);
1417+
1418+
try (Response response = httpClient.newCall(builder.build()).execute()) {
1419+
return parseResponse(response, ListGitProvidersResponse.class);
1420+
}
1421+
}
1422+
1423+
/**
1424+
* Deletes a configured Git provider.
1425+
*
1426+
* @param providerType the provider type to delete
1427+
* @throws IOException if the request fails
1428+
*/
1429+
public void deleteGitProvider(GitProviderType providerType) throws IOException {
1430+
logger.debug("Deleting Git provider: {}", providerType);
1431+
1432+
Request.Builder builder = new Request.Builder()
1433+
.url(config.getAgentUrl() + "/api/v1/code-governance/git-providers/" + providerType.getValue())
1434+
.delete();
1435+
1436+
addAuthHeaders(builder);
1437+
1438+
try (Response response = httpClient.newCall(builder.build()).execute()) {
1439+
handleErrorResponse(response);
1440+
}
1441+
}
1442+
1443+
/**
1444+
* Creates a Pull Request from LLM-generated code.
1445+
*
1446+
* @param request the PR creation request with repository info and files
1447+
* @return the created PR details
1448+
* @throws IOException if the request fails
1449+
*/
1450+
public CreatePRResponse createPR(CreatePRRequest request) throws IOException {
1451+
logger.debug("Creating PR: {} in {}/{}", request.getTitle(), request.getOwner(), request.getRepo());
1452+
1453+
String json = objectMapper.writeValueAsString(request);
1454+
RequestBody body = RequestBody.create(json, JSON);
1455+
1456+
Request.Builder builder = new Request.Builder()
1457+
.url(config.getAgentUrl() + "/api/v1/code-governance/prs")
1458+
.post(body);
1459+
1460+
addAuthHeaders(builder);
1461+
1462+
try (Response response = httpClient.newCall(builder.build()).execute()) {
1463+
return parseResponse(response, CreatePRResponse.class);
1464+
}
1465+
}
1466+
1467+
/**
1468+
* Lists PRs with optional filtering.
1469+
*
1470+
* @param options filtering options (limit, offset, state)
1471+
* @return list of PRs
1472+
* @throws IOException if the request fails
1473+
*/
1474+
public ListPRsResponse listPRs(ListPRsOptions options) throws IOException {
1475+
logger.debug("Listing PRs");
1476+
1477+
StringBuilder url = new StringBuilder(config.getAgentUrl() + "/api/v1/code-governance/prs");
1478+
StringBuilder query = new StringBuilder();
1479+
1480+
if (options != null) {
1481+
if (options.getLimit() != null) {
1482+
appendQueryParam(query, "limit", String.valueOf(options.getLimit()));
1483+
}
1484+
if (options.getOffset() != null) {
1485+
appendQueryParam(query, "offset", String.valueOf(options.getOffset()));
1486+
}
1487+
if (options.getState() != null) {
1488+
appendQueryParam(query, "state", options.getState());
1489+
}
1490+
}
1491+
1492+
if (query.length() > 0) {
1493+
url.append("?").append(query);
1494+
}
1495+
1496+
Request.Builder builder = new Request.Builder()
1497+
.url(url.toString())
1498+
.get();
1499+
1500+
addAuthHeaders(builder);
1501+
1502+
try (Response response = httpClient.newCall(builder.build()).execute()) {
1503+
return parseResponse(response, ListPRsResponse.class);
1504+
}
1505+
}
1506+
1507+
/**
1508+
* Lists PRs with default options.
1509+
*
1510+
* @return list of PRs
1511+
* @throws IOException if the request fails
1512+
*/
1513+
public ListPRsResponse listPRs() throws IOException {
1514+
return listPRs(null);
1515+
}
1516+
1517+
/**
1518+
* Gets a specific PR by ID.
1519+
*
1520+
* @param prId the PR record ID
1521+
* @return the PR record
1522+
* @throws IOException if the request fails
1523+
*/
1524+
public PRRecord getPR(String prId) throws IOException {
1525+
logger.debug("Getting PR: {}", prId);
1526+
1527+
Request.Builder builder = new Request.Builder()
1528+
.url(config.getAgentUrl() + "/api/v1/code-governance/prs/" + prId)
1529+
.get();
1530+
1531+
addAuthHeaders(builder);
1532+
1533+
try (Response response = httpClient.newCall(builder.build()).execute()) {
1534+
return parseResponse(response, PRRecord.class);
1535+
}
1536+
}
1537+
1538+
/**
1539+
* Syncs PR status from the Git provider.
1540+
*
1541+
* @param prId the PR record ID to sync
1542+
* @return the updated PR record
1543+
* @throws IOException if the request fails
1544+
*/
1545+
public PRRecord syncPRStatus(String prId) throws IOException {
1546+
logger.debug("Syncing PR status: {}", prId);
1547+
1548+
RequestBody body = RequestBody.create("{}", JSON);
1549+
1550+
Request.Builder builder = new Request.Builder()
1551+
.url(config.getAgentUrl() + "/api/v1/code-governance/prs/" + prId + "/sync")
1552+
.post(body);
1553+
1554+
addAuthHeaders(builder);
1555+
1556+
try (Response response = httpClient.newCall(builder.build()).execute()) {
1557+
return parseResponse(response, PRRecord.class);
1558+
}
1559+
}
1560+
13461561
@Override
13471562
public void close() {
13481563
httpClient.dispatcher().executorService().shutdown();
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright 2025 AxonFlow
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.getaxonflow.sdk.types.codegovernance;
17+
18+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
19+
import com.fasterxml.jackson.annotation.JsonProperty;
20+
21+
import java.util.Objects;
22+
23+
/**
24+
* A code file to include in a PR.
25+
*/
26+
@JsonIgnoreProperties(ignoreUnknown = true)
27+
public final class CodeFile {
28+
29+
@JsonProperty("path")
30+
private final String path;
31+
32+
@JsonProperty("content")
33+
private final String content;
34+
35+
@JsonProperty("language")
36+
private final String language;
37+
38+
@JsonProperty("action")
39+
private final FileAction action;
40+
41+
public CodeFile(
42+
@JsonProperty("path") String path,
43+
@JsonProperty("content") String content,
44+
@JsonProperty("language") String language,
45+
@JsonProperty("action") FileAction action) {
46+
this.path = Objects.requireNonNull(path, "path is required");
47+
this.content = Objects.requireNonNull(content, "content is required");
48+
this.language = language;
49+
this.action = Objects.requireNonNull(action, "action is required");
50+
}
51+
52+
public String getPath() {
53+
return path;
54+
}
55+
56+
public String getContent() {
57+
return content;
58+
}
59+
60+
public String getLanguage() {
61+
return language;
62+
}
63+
64+
public FileAction getAction() {
65+
return action;
66+
}
67+
68+
public static Builder builder() {
69+
return new Builder();
70+
}
71+
72+
public static class Builder {
73+
private String path;
74+
private String content;
75+
private String language;
76+
private FileAction action;
77+
78+
public Builder path(String path) {
79+
this.path = path;
80+
return this;
81+
}
82+
83+
public Builder content(String content) {
84+
this.content = content;
85+
return this;
86+
}
87+
88+
public Builder language(String language) {
89+
this.language = language;
90+
return this;
91+
}
92+
93+
public Builder action(FileAction action) {
94+
this.action = action;
95+
return this;
96+
}
97+
98+
public CodeFile build() {
99+
return new CodeFile(path, content, language, action);
100+
}
101+
}
102+
103+
@Override
104+
public boolean equals(Object o) {
105+
if (this == o) return true;
106+
if (o == null || getClass() != o.getClass()) return false;
107+
CodeFile codeFile = (CodeFile) o;
108+
return Objects.equals(path, codeFile.path) &&
109+
Objects.equals(content, codeFile.content) &&
110+
Objects.equals(language, codeFile.language) &&
111+
action == codeFile.action;
112+
}
113+
114+
@Override
115+
public int hashCode() {
116+
return Objects.hash(path, content, language, action);
117+
}
118+
119+
@Override
120+
public String toString() {
121+
return "CodeFile{" +
122+
"path='" + path + '\'' +
123+
", language='" + language + '\'' +
124+
", action=" + action +
125+
'}';
126+
}
127+
}

0 commit comments

Comments
 (0)