This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new b684cbf4946 NIFI-15673 Added support for Author and Committer with
git-based Flow Registry Clients (#10972)
b684cbf4946 is described below
commit b684cbf4946f3345aad13f2e8eda50f338932608
Author: Pierre Villard <[email protected]>
AuthorDate: Mon Jun 1 06:57:31 2026 -0700
NIFI-15673 Added support for Author and Committer with git-based Flow
Registry Clients (#10972)
Signed-off-by: David Handermann <[email protected]>
---
.../bitbucket/BitbucketRepositoryClient.java | 7 +++
.../azure/devops/AzureDevOpsRepositoryClient.java | 18 ++++---
.../flow/git/AbstractGitFlowRegistryClient.java | 56 +++++++++++++++++++++-
.../flow/git/client/GitCreateContentRequest.java | 24 ++++++++++
.../flow/git/client/GitRepositoryClient.java | 19 ++++++++
.../nifi-github-extensions/pom.xml | 6 +++
.../nifi/github/GitHubFlowRegistryClient.java | 2 +-
.../apache/nifi/github/GitHubRepositoryClient.java | 30 +++++++-----
.../nifi/github/GitHubFlowRegistryClientTest.java | 28 +++++++++++
nifi-extension-bundles/nifi-github-bundle/pom.xml | 2 +-
.../apache/nifi/gitlab/GitLabRepositoryClient.java | 19 ++++++--
11 files changed, 186 insertions(+), 25 deletions(-)
diff --git
a/nifi-extension-bundles/nifi-atlassian-bundle/nifi-atlassian-extensions/src/main/java/org/apache/nifi/atlassian/bitbucket/BitbucketRepositoryClient.java
b/nifi-extension-bundles/nifi-atlassian-bundle/nifi-atlassian-extensions/src/main/java/org/apache/nifi/atlassian/bitbucket/BitbucketRepositoryClient.java
index a1dc2adbf92..ca5c0066ab9 100644
---
a/nifi-extension-bundles/nifi-atlassian-bundle/nifi-atlassian-extensions/src/main/java/org/apache/nifi/atlassian/bitbucket/BitbucketRepositoryClient.java
+++
b/nifi-extension-bundles/nifi-atlassian-bundle/nifi-atlassian-extensions/src/main/java/org/apache/nifi/atlassian/bitbucket/BitbucketRepositoryClient.java
@@ -448,6 +448,13 @@ public class BitbucketRepositoryClient implements
GitRepositoryClient {
multipartBuilder.addPart(FIELD_BRANCH,
StandardHttpContentType.TEXT_PLAIN, branch.getBytes(StandardCharsets.UTF_8));
multipartBuilder.addPart(FIELD_PARENTS,
StandardHttpContentType.TEXT_PLAIN,
branchHead.getBytes(StandardCharsets.UTF_8));
+ final String authorName = request.getAuthorName();
+ final String authorEmail = request.getAuthorEmail();
+ if (authorName != null && authorEmail != null) {
+ final String authorValue = "%s <%s>".formatted(authorName,
authorEmail);
+ multipartBuilder.addPart(FIELD_AUTHOR,
StandardHttpContentType.TEXT_PLAIN,
authorValue.getBytes(StandardCharsets.UTF_8));
+ }
+
final HttpResponseEntity response =
this.webClient.getWebClientService()
.post()
.uri(uri)
diff --git
a/nifi-extension-bundles/nifi-azure-bundle/nifi-azure-registry-clients/src/main/java/org/apache/nifi/azure/devops/AzureDevOpsRepositoryClient.java
b/nifi-extension-bundles/nifi-azure-bundle/nifi-azure-registry-clients/src/main/java/org/apache/nifi/azure/devops/AzureDevOpsRepositoryClient.java
index dc6859317c0..cf4d2b2ea69 100644
---
a/nifi-extension-bundles/nifi-azure-bundle/nifi-azure-registry-clients/src/main/java/org/apache/nifi/azure/devops/AzureDevOpsRepositoryClient.java
+++
b/nifi-extension-bundles/nifi-azure-bundle/nifi-azure-registry-clients/src/main/java/org/apache/nifi/azure/devops/AzureDevOpsRepositoryClient.java
@@ -376,6 +376,10 @@ public class AzureDevOpsRepositoryClient implements
GitRepositoryClient {
.addQueryParameter(API, API_VERSION)
.build();
+ final String authorName = request.getAuthorName();
+ final String authorEmail = request.getAuthorEmail();
+ final Author author = (authorName != null && authorEmail != null) ?
new Author(authorName, authorEmail) : null;
+
for (int attempt = 1; attempt <= MAX_PUSH_ATTEMPTS; attempt++) {
if (expectedFileCommit != null) {
final Optional<String> currentFileCommit =
getContentSha(request.getPath(), branch);
@@ -385,7 +389,7 @@ public class AzureDevOpsRepositoryClient implements
GitRepositoryClient {
}
final String branchHead = fetchBranchHead(branch);
- final HttpResponseEntity response = executePush(pushUri, branch,
branchHead, encoded, message, changeType, path);
+ final HttpResponseEntity response = executePush(pushUri, branch,
branchHead, encoded, message, changeType, path, author);
if (response.statusCode() == HttpURLConnection.HTTP_CREATED) {
try {
@@ -421,10 +425,10 @@ public class AzureDevOpsRepositoryClient implements
GitRepositoryClient {
private HttpResponseEntity executePush(final URI pushUri, final String
branch, final String oldObjectId,
final String encodedContent, final
String message,
- final String changeType, final
String path) throws FlowRegistryException {
+ final String changeType, final
String path, final Author author) throws FlowRegistryException {
final PushRequest pushRequest = new PushRequest(
List.of(new RefUpdate(REFS_HEADS_PREFIX + branch,
oldObjectId)),
- List.of(new Commit(message, List.of(new Change(changeType, new
Item(path), new NewContent(encodedContent, CONTENT_TYPE_BASE64)))))
+ List.of(new Commit(message, List.of(new Change(changeType, new
Item(path), new NewContent(encodedContent, CONTENT_TYPE_BASE64))), author))
);
final String json;
@@ -455,8 +459,7 @@ public class AzureDevOpsRepositoryClient implements
GitRepositoryClient {
final PushRequest pushRequest = new PushRequest(
List.of(new RefUpdate(REFS_HEADS_PREFIX + branch,
oldObjectId)),
- List.of(new Commit(commitMessage,
- List.of(new Change(CHANGE_TYPE_DELETE, new Item(path),
null))))
+ List.of(new Commit(commitMessage, List.of(new
Change(CHANGE_TYPE_DELETE, new Item(path), null)), null))
);
final String json = MAPPER.writeValueAsString(pushRequest);
@@ -506,7 +509,10 @@ public class AzureDevOpsRepositoryClient implements
GitRepositoryClient {
private record RefUpdate(String name, String oldObjectId) { }
- private record Commit(String comment, List<Change> changes) { }
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ private record Commit(String comment, List<Change> changes, Author author)
{ }
+
+ private record Author(String name, String email) { }
private record Item(String path) { }
diff --git
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/AbstractGitFlowRegistryClient.java
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/AbstractGitFlowRegistryClient.java
index b866f9d604c..740763b7296 100644
---
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/AbstractGitFlowRegistryClient.java
+++
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/AbstractGitFlowRegistryClient.java
@@ -119,6 +119,18 @@ public abstract class AbstractGitFlowRegistryClient
extends AbstractFlowRegistry
.identifiesControllerService(SSLContextProvider.class)
.build();
+ public static final PropertyDescriptor COMMIT_AUTHOR_SOURCE = new
PropertyDescriptor.Builder()
+ .name("Commit Author Source")
+ .description("""
+ Specifies how the commit author is determined for Git
commits. \
+ When set to Service User, the authenticated service
account is used as the commit author. \
+ When set to Application User, the identity of the NiFi
user performing the action is used as \
+ both the author name and author email, while the service
account remains the committer.""")
+ .allowableValues(CommitAuthorSource.class)
+ .defaultValue(CommitAuthorSource.SERVICE_USER)
+ .required(true)
+ .build();
+
static final String DEFAULT_BUCKET_NAME = "default";
static final String DEFAULT_BUCKET_KEEP_FILE_PATH = DEFAULT_BUCKET_NAME +
"/.keep";
static final String DEFAULT_BUCKET_KEEP_FILE_CONTENT = "Do Not Delete";
@@ -148,6 +160,7 @@ public abstract class AbstractGitFlowRegistryClient extends
AbstractFlowRegistry
combinedPropertyDescriptors.add(REPOSITORY_PATH);
combinedPropertyDescriptors.add(DIRECTORY_FILTER_EXCLUDE);
combinedPropertyDescriptors.add(PARAMETER_CONTEXT_VALUES);
+ combinedPropertyDescriptors.add(COMMIT_AUTHOR_SOURCE);
combinedPropertyDescriptors.add(SSL_CONTEXT_SERVICE);
propertyDescriptors =
Collections.unmodifiableList(combinedPropertyDescriptors);
@@ -238,6 +251,7 @@ public abstract class AbstractGitFlowRegistryClient extends
AbstractFlowRegistry
final FlowLocation flowLocation = new FlowLocation(branch,
flow.getBucketIdentifier(), flow.getIdentifier());
final String filePath = getSnapshotFilePath(flowLocation);
final String commitMessage =
REGISTER_FLOW_MESSAGE_FORMAT.formatted(flow.getIdentifier());
+ final String userIdentity = resolveAuthorIdentity(context);
final Optional<String> existingFileSha =
repositoryClient.getContentSha(filePath, branch);
if (existingFileSha.isPresent()) {
@@ -258,6 +272,8 @@ public abstract class AbstractGitFlowRegistryClient extends
AbstractFlowRegistry
.path(filePath)
.content(flowSnapshotSerializer.serialize(flowSnapshot))
.message(commitMessage)
+ .authorName(userIdentity)
+ .authorEmail(userIdentity)
.build();
repositoryClient.createContent(request);
@@ -278,7 +294,8 @@ public abstract class AbstractGitFlowRegistryClient extends
AbstractFlowRegistry
final String branch = flowLocation.getBranch();
final String filePath = getSnapshotFilePath(flowLocation);
final String commitMessage =
DEREGISTER_FLOW_MESSAGE_FORMAT.formatted(flowLocation.getFlowId());
- try (final InputStream deletedSnapshotContent =
repositoryClient.deleteContent(filePath, commitMessage, branch)) {
+ final String userIdentity = resolveAuthorIdentity(context);
+ try (final InputStream deletedSnapshotContent =
repositoryClient.deleteContent(filePath, commitMessage, branch, userIdentity,
userIdentity)) {
final RegisteredFlowSnapshot deletedSnapshot =
getSnapshot(deletedSnapshotContent);
populateFlowAndSnapshotMetadata(deletedSnapshot, flowLocation);
updateBucketReferences(repositoryClient, deletedSnapshot,
flowLocation.getBucketId());
@@ -437,6 +454,8 @@ public abstract class AbstractGitFlowRegistryClient extends
AbstractFlowRegistry
final String originalFlowContentsGroupId =
replaceGroupId(flowSnapshot.getFlowContents(), FLOW_CONTENTS_GROUP_ID);
final Position originalFlowContentsPosition =
replacePosition(flowSnapshot.getFlowContents(), new Position(0, 0));
+ final String userIdentity = resolveAuthorIdentity(context);
+
final GitCreateContentRequest createContentRequest =
GitCreateContentRequest.builder()
.branch(branch)
.path(filePath)
@@ -444,6 +463,8 @@ public abstract class AbstractGitFlowRegistryClient extends
AbstractFlowRegistry
.message(commitMessage)
.existingContentSha(existingBlobSha)
.expectedCommitSha(expectedVersion)
+ .authorName(userIdentity)
+ .authorEmail(userIdentity)
.build();
final String createContentCommitSha =
repositoryClient.createContent(createContentRequest);
@@ -656,6 +677,11 @@ public abstract class AbstractGitFlowRegistryClient
extends AbstractFlowRegistry
}
}
+ private String resolveAuthorIdentity(final
FlowRegistryClientConfigurationContext context) {
+ final CommitAuthorSource source =
context.getProperty(COMMIT_AUTHOR_SOURCE).asAllowableValue(CommitAuthorSource.class);
+ return CommitAuthorSource.APPLICATION_USER.equals(source) ?
context.getNiFiUserIdentity().orElse(null) : null;
+ }
+
private void verifyReadPermissions(final GitRepositoryClient
repositoryClient) throws AuthorizationException {
if (!repositoryClient.hasReadPermission()) {
throw new AuthorizationException("Client does not have read access
to the repository");
@@ -839,6 +865,34 @@ public abstract class AbstractGitFlowRegistryClient
extends AbstractFlowRegistry
return new JacksonFlowSnapshotSerializer();
}
+ enum CommitAuthorSource implements DescribedValue {
+ SERVICE_USER("Service User", "The commit author is the authenticated
service account configured on this registry client"),
+ APPLICATION_USER("Application User", "The commit author is the NiFi
user performing the action, using the identity as both author name and author
email");
+
+ private final String displayName;
+ private final String description;
+
+ CommitAuthorSource(final String displayName, final String description)
{
+ this.displayName = displayName;
+ this.description = description;
+ }
+
+ @Override
+ public String getValue() {
+ return name();
+ }
+
+ @Override
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+ }
+
enum ParameterContextValuesStrategy implements DescribedValue {
RETAIN("Retain", "Retain Values in Parameter Contexts without
modifications"),
REMOVE("Remove", "Remove Values from Parameter Context"),
diff --git
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/client/GitCreateContentRequest.java
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/client/GitCreateContentRequest.java
index 3c8729bd25a..dd8d4986058 100644
---
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/client/GitCreateContentRequest.java
+++
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/client/GitCreateContentRequest.java
@@ -27,6 +27,8 @@ public class GitCreateContentRequest {
private final String message;
private final String existingContentSha;
private final String expectedCommitSha;
+ private final String authorName;
+ private final String authorEmail;
private GitCreateContentRequest(final Builder builder) {
this.branch = Objects.requireNonNull(builder.branch);
@@ -37,6 +39,8 @@ public class GitCreateContentRequest {
this.existingContentSha = builder.existingContentSha;
// Commit SHA for providers that support atomic commits via commit SHA
this.expectedCommitSha = builder.expectedCommitSha;
+ this.authorName = builder.authorName;
+ this.authorEmail = builder.authorEmail;
}
public String getBranch() {
@@ -63,6 +67,14 @@ public class GitCreateContentRequest {
return expectedCommitSha;
}
+ public String getAuthorName() {
+ return authorName;
+ }
+
+ public String getAuthorEmail() {
+ return authorEmail;
+ }
+
public static Builder builder() {
return new Builder();
}
@@ -74,6 +86,8 @@ public class GitCreateContentRequest {
private String message;
private String existingContentSha;
private String expectedCommitSha;
+ private String authorName;
+ private String authorEmail;
public Builder branch(final String branch) {
this.branch = branch;
@@ -105,6 +119,16 @@ public class GitCreateContentRequest {
return this;
}
+ public Builder authorName(final String authorName) {
+ this.authorName = authorName;
+ return this;
+ }
+
+ public Builder authorEmail(final String authorEmail) {
+ this.authorEmail = authorEmail;
+ return this;
+ }
+
public GitCreateContentRequest build() {
return new GitCreateContentRequest(this);
}
diff --git
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/client/GitRepositoryClient.java
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/client/GitRepositoryClient.java
index 3d02cdbeaba..6c2853c71b5 100644
---
a/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/client/GitRepositoryClient.java
+++
b/nifi-extension-bundles/nifi-extension-utils/nifi-git-flow-registry/src/main/java/org/apache/nifi/registry/flow/git/client/GitRepositoryClient.java
@@ -155,6 +155,25 @@ public interface GitRepositoryClient {
*/
InputStream deleteContent(String filePath, String commitMessage, String
branch) throws FlowRegistryException, IOException;
+ /**
+ * Deletes the file at the given path on the given branch, attributing the
commit to the specified author.
+ *
+ * The caller of this method is responsible for closing the returned
InputStream.
+ *
+ * @param filePath the path of the file
+ * @param commitMessage the commit message
+ * @param branch the branch
+ * @param authorName the name of the commit author, or null to use the
authenticated user
+ * @param authorEmail the email of the commit author, or null to use the
authenticated user
+ * @return the input stream to the deleted content
+ * @throws IOException if an I/O error occurs
+ * @throws FlowRegistryException if a non-I/O error occurs
+ */
+ default InputStream deleteContent(final String filePath, final String
commitMessage, final String branch,
+ final String authorName, final String
authorEmail) throws FlowRegistryException, IOException {
+ return deleteContent(filePath, commitMessage, branch);
+ }
+
/**
* Closes any resources held by the client.
*
diff --git
a/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/pom.xml
b/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/pom.xml
index 1eb89489df7..477a25227bf 100644
--- a/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/pom.xml
+++ b/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/pom.xml
@@ -38,6 +38,12 @@
<groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId>
<version>${github-api.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>com.infradna.tool</groupId>
+ <artifactId>bridge-method-annotation</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
diff --git
a/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/main/java/org/apache/nifi/github/GitHubFlowRegistryClient.java
b/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/main/java/org/apache/nifi/github/GitHubFlowRegistryClient.java
index da085231eb5..668c2cfc574 100644
---
a/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/main/java/org/apache/nifi/github/GitHubFlowRegistryClient.java
+++
b/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/main/java/org/apache/nifi/github/GitHubFlowRegistryClient.java
@@ -115,7 +115,7 @@ public class GitHubFlowRegistryClient extends
AbstractGitFlowRegistryClient {
}
@Override
- protected GitHubRepositoryClient createRepositoryClient(final
FlowRegistryClientConfigurationContext context) throws IOException,
FlowRegistryException {
+ protected GitRepositoryClient createRepositoryClient(final
FlowRegistryClientConfigurationContext context) throws IOException,
FlowRegistryException {
return GitHubRepositoryClient.builder()
.logger(getLogger())
.apiUrl(context.getProperty(GITHUB_API_URL).getValue())
diff --git
a/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/main/java/org/apache/nifi/github/GitHubRepositoryClient.java
b/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/main/java/org/apache/nifi/github/GitHubRepositoryClient.java
index ca20991d8c1..0a023b8cda6 100644
---
a/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/main/java/org/apache/nifi/github/GitHubRepositoryClient.java
+++
b/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/main/java/org/apache/nifi/github/GitHubRepositoryClient.java
@@ -29,11 +29,13 @@ import
org.apache.nifi.registry.flow.git.client.GitRepositoryClient;
import org.apache.nifi.ssl.SSLContextProvider;
import org.kohsuke.github.GHCommit;
import org.kohsuke.github.GHContent;
+import org.kohsuke.github.GHContentBuilder;
import org.kohsuke.github.GHContentUpdateResponse;
import org.kohsuke.github.GHMyself;
import org.kohsuke.github.GHPermissionType;
import org.kohsuke.github.GHRef;
import org.kohsuke.github.GHRepository;
+import org.kohsuke.github.GHUser;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubAbuseLimitHandler;
import org.kohsuke.github.GitHubBuilder;
@@ -50,7 +52,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.http.HttpClient;
import java.security.PrivateKey;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@@ -201,13 +202,20 @@ public class GitHubRepositoryClient implements
GitRepositoryClient {
logger.debug("Creating content at path [{}] on branch [{}] in repo
[{}] ", resolvedPath, branch, repository.getName());
return execute(() -> {
try {
- final GHContentUpdateResponse response =
repository.createContent()
+ final GHContentBuilder contentBuilder =
repository.createContent()
.branch(branch)
.path(resolvedPath)
.content(request.getContent())
.message(request.getMessage())
- .sha(request.getExistingContentSha())
- .commit();
+ .sha(request.getExistingContentSha());
+
+ final String authorName = request.getAuthorName();
+ final String authorEmail = request.getAuthorEmail();
+ if (authorName != null && authorEmail != null) {
+ contentBuilder.author(authorName, authorEmail);
+ }
+
+ final GHContentUpdateResponse response =
contentBuilder.commit();
return response.getCommit().getSha();
} catch (final FileNotFoundException fnf) {
throwPathOrBranchNotFound(fnf, resolvedPath, branch);
@@ -477,15 +485,13 @@ public class GitHubRepositoryClient implements
GitRepositoryClient {
if (commit == null) {
final GHCommit.ShortInfo shortInfo = ghCommit.getCommitShortInfo();
- final String author = ghCommit.getAuthor() != null
- ? ghCommit.getAuthor().getLogin()
- : shortInfo.getAuthor().getName();
-
+ final GHUser ghUser = ghCommit.getAuthor();
+ final String author = ghUser != null ? ghUser.getLogin() :
shortInfo.getAuthor().getName();
commit = new GitCommit(
- ghCommit.getSHA1(),
- author,
- shortInfo.getMessage(),
- Instant.ofEpochMilli(shortInfo.getCommitDate().getTime()));
+ ghCommit.getSHA1(),
+ author,
+ shortInfo.getMessage(),
+ shortInfo.getCommitDate());
commitCache.put(ghCommit.getSHA1(), commit);
}
diff --git
a/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/test/java/org/apache/nifi/github/GitHubFlowRegistryClientTest.java
b/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/test/java/org/apache/nifi/github/GitHubFlowRegistryClientTest.java
index e7a0a49e27a..6683dfbe0f5 100644
---
a/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/test/java/org/apache/nifi/github/GitHubFlowRegistryClientTest.java
+++
b/nifi-extension-bundles/nifi-github-bundle/nifi-github-extensions/src/test/java/org/apache/nifi/github/GitHubFlowRegistryClientTest.java
@@ -130,6 +130,29 @@ public class GitHubFlowRegistryClientTest {
assertEquals("%s/%s.json".formatted(incomingFlow.getBucketIdentifier(),
incomingFlow.getIdentifier()), capturedArgument.getPath());
assertEquals(serializedSnapshotContent, capturedArgument.getContent());
assertNull(capturedArgument.getExistingContentSha());
+ assertEquals("[email protected]", capturedArgument.getAuthorName());
+ assertEquals("[email protected]",
capturedArgument.getAuthorEmail());
+ }
+
+ @Test
+ public void testRegisterFlowWithServiceUserAuthor() throws IOException,
FlowRegistryException {
+ setupClientConfigurationContextWithDefaults();
+
+ final PropertyValue commitAuthorPropertyValue =
createMockPropertyValueWithEnum("SERVICE_USER");
+
when(clientConfigurationContext.getProperty(GitHubFlowRegistryClient.COMMIT_AUTHOR_SOURCE)).thenReturn(commitAuthorPropertyValue);
+
+ final String serializedSnapshotContent = "placeholder";
+
when(flowSnapshotSerializer.serialize(any(RegisteredFlowSnapshot.class))).thenReturn(serializedSnapshotContent);
+
+ final RegisteredFlow incomingFlow = createIncomingRegisteredFlow();
+ flowRegistryClient.registerFlow(clientConfigurationContext,
incomingFlow);
+
+ final ArgumentCaptor<GitCreateContentRequest> argumentCaptor =
ArgumentCaptor.forClass(GitCreateContentRequest.class);
+ verify(repositoryClient).createContent(argumentCaptor.capture());
+
+ final GitCreateContentRequest capturedArgument =
argumentCaptor.getValue();
+ assertNull(capturedArgument.getAuthorName());
+ assertNull(capturedArgument.getAuthorEmail());
}
@Test
@@ -433,6 +456,11 @@ public class GitHubFlowRegistryClientTest {
final PropertyValue parametersPropertyValue =
createMockPropertyValue("Retain");
when(clientConfigurationContext.getProperty(GitHubFlowRegistryClient.PARAMETER_CONTEXT_VALUES)).thenReturn(parametersPropertyValue);
+
+ final PropertyValue commitAuthorPropertyValue =
createMockPropertyValueWithEnum("APPLICATION_USER");
+
when(clientConfigurationContext.getProperty(GitHubFlowRegistryClient.COMMIT_AUTHOR_SOURCE)).thenReturn(commitAuthorPropertyValue);
+
+
when(clientConfigurationContext.getNiFiUserIdentity()).thenReturn(Optional.of("[email protected]"));
}
private void setupClientConfigurationContextWithDefaults() {
diff --git a/nifi-extension-bundles/nifi-github-bundle/pom.xml
b/nifi-extension-bundles/nifi-github-bundle/pom.xml
index dc4a68230b6..68f4c246698 100644
--- a/nifi-extension-bundles/nifi-github-bundle/pom.xml
+++ b/nifi-extension-bundles/nifi-github-bundle/pom.xml
@@ -26,7 +26,7 @@
<packaging>pom</packaging>
<properties>
- <github-api.version>1.330</github-api.version>
+ <github-api.version>2.0-rc.6</github-api.version>
</properties>
<modules>
diff --git
a/nifi-extension-bundles/nifi-gitlab-bundle/nifi-gitlab-extensions/src/main/java/org/apache/nifi/gitlab/GitLabRepositoryClient.java
b/nifi-extension-bundles/nifi-gitlab-bundle/nifi-gitlab-extensions/src/main/java/org/apache/nifi/gitlab/GitLabRepositoryClient.java
index a6292e4ab28..14eeb0ede65 100644
---
a/nifi-extension-bundles/nifi-gitlab-bundle/nifi-gitlab-extensions/src/main/java/org/apache/nifi/gitlab/GitLabRepositoryClient.java
+++
b/nifi-extension-bundles/nifi-gitlab-bundle/nifi-gitlab-extensions/src/main/java/org/apache/nifi/gitlab/GitLabRepositoryClient.java
@@ -270,9 +270,9 @@ public class GitLabRepositoryClient implements
GitRepositoryClient {
projectPath,
branch,
request.getMessage(),
- null, // start_branch - null means use the branch
parameter
- null, // author_email - null means use the
authenticated user
- null, // author_name - null means use the
authenticated user
+ null,
+ request.getAuthorEmail(),
+ request.getAuthorName(),
List.of(commitAction));
final String commitId = commit.getId();
@@ -284,11 +284,22 @@ public class GitLabRepositoryClient implements
GitRepositoryClient {
@Override
public InputStream deleteContent(final String filePath, final String
commitMessage, final String branch) throws FlowRegistryException {
+ return deleteContent(filePath, commitMessage, branch, null, null);
+ }
+
+ @Override
+ public InputStream deleteContent(final String filePath, final String
commitMessage, final String branch,
+ final String authorName, final String
authorEmail) throws FlowRegistryException {
final String resolvedPath = getResolvedPath(filePath);
logger.debug("Deleting content at path [{}] on branch [{}] in
repository [{}] ", resolvedPath, branch, projectPath);
return execute(() -> {
final InputStream content =
gitLab.getRepositoryFileApi().getRawFile(projectPath, branch, resolvedPath);
- gitLab.getRepositoryFileApi().deleteFile(projectPath,
resolvedPath, branch, commitMessage);
+
+ final CommitAction commitAction = new CommitAction();
+ commitAction.setAction(CommitAction.Action.DELETE);
+ commitAction.setFilePath(resolvedPath);
+
+ gitLab.getCommitsApi().createCommit(projectPath, branch,
commitMessage, null, authorEmail, authorName, List.of(commitAction));
return content;
});
}