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 1779663445a5..bf4dadbecaa7 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 @@ -438,6 +438,13 @@ private String createContentCloud(final GitCreateContentRequest request, final S multipartBuilder.addPart(FIELD_PARENTS, StandardHttpContentType.TEXT_PLAIN, expectedCommitSha.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 URI uri = getRepositoryUriBuilder().addPathSegment("src").build(); final String errorMessage = "Error while committing content for repository [%s] on branch %s at path %s" .formatted(repoName, branch, resolvedPath); 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 88091ff978ea..0111912bde72 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 @@ -390,10 +390,13 @@ public String createContent(final GitCreateContentRequest request) throws FlowRe final String encoded = Base64.getEncoder().encodeToString(request.getContent().getBytes(StandardCharsets.UTF_8)); + final String authorName = request.getAuthorName(); + final String authorEmail = request.getAuthorEmail(); + final Author author = (authorName != null && authorEmail != null) ? new Author(authorName, authorEmail) : null; + 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(encoded, CONTENT_TYPE_BASE64))))) + List.of(new Commit(message, List.of(new Change(changeType, new Item(path), new NewContent(encoded, CONTENT_TYPE_BASE64))), author)) ); final String json; @@ -440,8 +443,7 @@ public InputStream deleteContent(final String filePath, final String commitMessa 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); @@ -491,7 +493,10 @@ private record PushRequest(List refUpdates, List commits) { } private record RefUpdate(String name, String oldObjectId) { } - private record Commit(String comment, List changes) { } + @JsonInclude(JsonInclude.Include.NON_NULL) + private record Commit(String comment, List 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 b866f9d604cb..b2da0a52d09b 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 @@ -238,6 +238,7 @@ public RegisteredFlow registerFlow(final FlowRegistryClientConfigurationContext 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 = context.getNiFiUserIdentity().orElse(null); final Optional existingFileSha = repositoryClient.getContentSha(filePath, branch); if (existingFileSha.isPresent()) { @@ -258,6 +259,8 @@ public RegisteredFlow registerFlow(final FlowRegistryClientConfigurationContext .path(filePath) .content(flowSnapshotSerializer.serialize(flowSnapshot)) .message(commitMessage) + .authorName(userIdentity) + .authorEmail(userIdentity) .build(); repositoryClient.createContent(request); @@ -278,7 +281,8 @@ public RegisteredFlow deregisterFlow(final FlowRegistryClientConfigurationContex 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 = context.getNiFiUserIdentity().orElse(null); + 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 +441,8 @@ public RegisteredFlowSnapshot registerFlowSnapshot(final FlowRegistryClientConfi final String originalFlowContentsGroupId = replaceGroupId(flowSnapshot.getFlowContents(), FLOW_CONTENTS_GROUP_ID); final Position originalFlowContentsPosition = replacePosition(flowSnapshot.getFlowContents(), new Position(0, 0)); + final String userIdentity = context.getNiFiUserIdentity().orElse(null); + final GitCreateContentRequest createContentRequest = GitCreateContentRequest.builder() .branch(branch) .path(filePath) @@ -444,6 +450,8 @@ public RegisteredFlowSnapshot registerFlowSnapshot(final FlowRegistryClientConfi .message(commitMessage) .existingContentSha(existingBlobSha) .expectedCommitSha(expectedVersion) + .authorName(userIdentity) + .authorEmail(userIdentity) .build(); final String createContentCommitSha = repositoryClient.createContent(createContentRequest); 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 3c8729bd25a0..dd8d49860587 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 @@ private GitCreateContentRequest(final Builder builder) { 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 String getExpectedCommitSha() { return expectedCommitSha; } + public String getAuthorName() { + return authorName; + } + + public String getAuthorEmail() { + return authorEmail; + } + public static Builder builder() { return new Builder(); } @@ -74,6 +86,8 @@ public static final class Builder { 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 Builder expectedCommitSha(final String expectedCommitSha) { 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 3d02cdbeaba1..6c2853c71b5d 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 @@ default Optional getContentShaAtCommit(String path, String commitSha) th */ 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 29cd7ef9846d..528521016bae 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 @@ org.kohsuke github-api ${github-api.version} + + + com.infradna.tool + bridge-method-annotation + + io.jsonwebtoken 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 da085231eb50..668c2cfc5748 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 @@ protected List createPropertyDescriptors() { } @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 3c1af3a2c498..55d84dff34bc 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.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; @@ -48,9 +50,10 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; 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 +204,20 @@ public String createContent(final GitCreateContentRequest request) throws IOExce 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) { + setContentBuilderAuthor(contentBuilder, authorName, authorEmail); + } + + final GHContentUpdateResponse response = contentBuilder.commit(); return response.getCommit().getSha(); } catch (final FileNotFoundException fnf) { throwPathOrBranchNotFound(fnf, resolvedPath, branch); @@ -472,17 +482,37 @@ private void throwPathOrBranchNotFound(final FileNotFoundException fileNotFoundE throw new FlowRegistryException("Path [" + path + "] or Branch [" + branch + "] not found", fileNotFoundException); } + /** + * Sets the author on a GHContentBuilder using reflection because Hub4j does not yet expose an author() method. + * The internal Requester supports with(String, Map) which maps to the GitHub API's author JSON object. + * This workaround can be replaced with contentBuilder.author(name, email) once Hub4j adds that method. + */ + private void setContentBuilderAuthor(final GHContentBuilder contentBuilder, final String authorName, final String authorEmail) { + try { + final Field reqField = GHContentBuilder.class.getDeclaredField("req"); + reqField.setAccessible(true); + final Object requester = reqField.get(contentBuilder); + final Method withMethod = requester.getClass().getMethod("with", String.class, Map.class); + withMethod.setAccessible(true); + withMethod.invoke(requester, "author", Map.of("name", authorName, "email", authorEmail)); + } catch (final ReflectiveOperationException e) { + logger.warn("Unable to set commit author via GHContentBuilder reflection; commit will use the authenticated service account as author", e); + } + } + private GitCommit toGitCommit(final GHCommit ghCommit) throws IOException { GitCommit commit = commitCache.getIfPresent(ghCommit.getSHA1()); if (commit != null) { return commit; } else { final GHCommit.ShortInfo shortInfo = ghCommit.getCommitShortInfo(); + final GHUser ghUser = ghCommit.getAuthor(); + final String author = ghUser != null ? ghUser.getLogin() : shortInfo.getAuthor().getName(); commit = new GitCommit( ghCommit.getSHA1(), - ghCommit.getAuthor().getLogin(), + author, shortInfo.getMessage(), - Instant.ofEpochMilli(shortInfo.getCommitDate().getTime())); + shortInfo.getCommitDate()); commitCache.put(ghCommit.getSHA1(), commit); return 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 e7a0a49e27a5..c54aec9f500b 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 @@ -32,6 +32,7 @@ import org.apache.nifi.registry.flow.RegisteredFlowSnapshotMetadata; import org.apache.nifi.registry.flow.git.client.GitCommit; import org.apache.nifi.registry.flow.git.client.GitCreateContentRequest; +import org.apache.nifi.registry.flow.git.client.GitRepositoryClient; import org.apache.nifi.registry.flow.git.serialize.FlowSnapshotSerializer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -50,7 +51,6 @@ import java.util.function.Function; import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -58,6 +58,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -69,7 +70,7 @@ public class GitHubFlowRegistryClientTest { static final String DEFAULT_REPO_BRANCH = "some-branch"; static final String DEFAULT_FILTER = "[.].*"; - private GitHubRepositoryClient repositoryClient; + private GitRepositoryClient repositoryClient; private FlowSnapshotSerializer flowSnapshotSerializer; private GitHubFlowRegistryClient flowRegistryClient; private FlowRegistryClientConfigurationContext clientConfigurationContext; @@ -77,7 +78,7 @@ public class GitHubFlowRegistryClientTest { @BeforeEach public void setup() throws IOException, FlowRegistryException { - repositoryClient = mock(GitHubRepositoryClient.class); + repositoryClient = mock(GitRepositoryClient.class); flowSnapshotSerializer = mock(FlowSnapshotSerializer.class); flowRegistryClient = new TestableGitHubRepositoryClient(repositoryClient, flowSnapshotSerializer); @@ -94,10 +95,10 @@ public void setup() throws IOException, FlowRegistryException { } @Test - public void testGitHubClientInitializationFailsWithIncompatibleJackson() { - assertDoesNotThrow(() -> new GitHubBuilder() + public void testGitHubClientInitializationFailsWithIncompatibleJackson() throws IOException { + new GitHubBuilder() .withEndpoint("https://api.github.com") - .build()); + .build(); } @Test @@ -130,6 +131,8 @@ public void testRegisterFlow() throws IOException, FlowRegistryException { assertEquals("%s/%s.json".formatted(incomingFlow.getBucketIdentifier(), incomingFlow.getIdentifier()), capturedArgument.getPath()); assertEquals(serializedSnapshotContent, capturedArgument.getContent()); assertNull(capturedArgument.getExistingContentSha()); + assertEquals("test-user@example.com", capturedArgument.getAuthorName()); + assertEquals("test-user@example.com", capturedArgument.getAuthorEmail()); } @Test @@ -184,6 +187,13 @@ public void testRegisterFlowSnapshot() throws IOException, FlowRegistryException assertNotNull(resultBucket); assertEquals(incomingMetadata.getBucketIdentifier(), resultBucket.getIdentifier()); assertEquals(incomingMetadata.getBucketIdentifier(), resultBucket.getName()); + + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(GitCreateContentRequest.class); + verify(repositoryClient).createContent(argumentCaptor.capture()); + + final GitCreateContentRequest capturedRequest = argumentCaptor.getValue(); + assertEquals("test-user@example.com", capturedRequest.getAuthorName()); + assertEquals("test-user@example.com", capturedRequest.getAuthorEmail()); } @Test @@ -422,6 +432,10 @@ private RegisteredFlow createIncomingRegisteredFlow() { } private void setupClientConfigurationContext(final String repoPath, final String branch) { + setupClientConfigurationContext(repoPath, branch, Optional.of("test-user@example.com")); + } + + private void setupClientConfigurationContext(final String repoPath, final String branch, final Optional userIdentity) { final PropertyValue repoPathPropertyValue = createMockPropertyValue(repoPath); when(clientConfigurationContext.getProperty(GitHubFlowRegistryClient.REPOSITORY_PATH)).thenReturn(repoPathPropertyValue); @@ -433,6 +447,8 @@ private void setupClientConfigurationContext(final String repoPath, final String final PropertyValue parametersPropertyValue = createMockPropertyValue("Retain"); when(clientConfigurationContext.getProperty(GitHubFlowRegistryClient.PARAMETER_CONTEXT_VALUES)).thenReturn(parametersPropertyValue); + + when(clientConfigurationContext.getNiFiUserIdentity()).thenReturn(userIdentity); } private void setupClientConfigurationContextWithDefaults() { @@ -449,37 +465,40 @@ private PropertyValue createMockPropertyValueWithEnum(final String value) { final PropertyValue propertyValue = mock(PropertyValue.class); when(propertyValue.getValue()).thenReturn(value); - // Mock asAllowableValue to find the enum constant that matches the string value - when(propertyValue.asAllowableValue(any())).thenAnswer(invocation -> { - Class clazz = invocation.getArgument(0); + doAnswer(invocation -> { + final Class clazz = invocation.getArgument(0); if (clazz.isEnum()) { - Object[] enumConstants = clazz.getEnumConstants(); - for (Object enumConstant : enumConstants) { + for (final Object enumConstant : clazz.getEnumConstants()) { if (value.equals(enumConstant.toString())) { return enumConstant; } } } return null; - }); + }).when(propertyValue).asAllowableValue(any()); return propertyValue; } private static class TestableGitHubRepositoryClient extends GitHubFlowRegistryClient { - private final GitHubRepositoryClient repositoryClient; + private final GitRepositoryClient repositoryClient; private final FlowSnapshotSerializer flowSnapshotSerializer; - public TestableGitHubRepositoryClient(final GitHubRepositoryClient repositoryClient, final FlowSnapshotSerializer flowSnapshotSerializer) { + public TestableGitHubRepositoryClient(final GitRepositoryClient repositoryClient, final FlowSnapshotSerializer flowSnapshotSerializer) { this.repositoryClient = repositoryClient; this.flowSnapshotSerializer = flowSnapshotSerializer; } @Override - protected GitHubRepositoryClient createRepositoryClient(final FlowRegistryClientConfigurationContext context) throws IOException, FlowRegistryException { + protected GitRepositoryClient createRepositoryClient(final FlowRegistryClientConfigurationContext context) throws IOException, FlowRegistryException { return repositoryClient; } + @Override + protected String getStorageLocation(final GitRepositoryClient repositoryClient) { + return "git@github.com:test-owner/test-repo.git"; + } + @Override protected FlowSnapshotSerializer createFlowSnapshotSerializer() { return flowSnapshotSerializer; diff --git a/nifi-extension-bundles/nifi-github-bundle/pom.xml b/nifi-extension-bundles/nifi-github-bundle/pom.xml index d4ac06e9c503..fd473218846e 100644 --- a/nifi-extension-bundles/nifi-github-bundle/pom.xml +++ b/nifi-extension-bundles/nifi-github-bundle/pom.xml @@ -26,7 +26,7 @@ pom - 1.330 + 2.0-rc.5 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 a6292e4ab283..14eeb0ede65e 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 String createContent(final GitCreateContentRequest request) throws FlowRe 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 String createContent(final GitCreateContentRequest request) throws FlowRe @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; }); }