exceptionfactory commented on code in PR #10166:
URL: https://github.com/apache/nifi/pull/10166#discussion_r2328450293


##########
nifi-extension-bundles/nifi-azure-bundle/nifi-azure-registry-clients/src/main/java/org/apache/nifi/azure/devops/AzureDevOpsRepositoryClient.java:
##########
@@ -0,0 +1,739 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.nifi.azure.devops;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.nifi.oauth2.OAuth2AccessTokenProvider;
+import org.apache.nifi.registry.flow.FlowRegistryException;
+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.web.client.api.HttpResponseEntity;
+import org.apache.nifi.web.client.api.HttpUriBuilder;
+import org.apache.nifi.web.client.api.MediaType;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Git Repository Client implementation for Azure DevOps using the REST API.
+ */
+public class AzureDevOpsRepositoryClient implements GitRepositoryClient {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(AzureDevOpsRepositoryClient.class);

Review Comment:
   Passing the `ComponentLog` would enable associating logs with the Flow 
Registry instance, instead of just passing the component identifier.



##########
nifi-extension-bundles/nifi-azure-bundle/nifi-azure-registry-clients/src/main/java/org/apache/nifi/azure/devops/AzureDevOpsRepositoryClient.java:
##########
@@ -0,0 +1,739 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.nifi.azure.devops;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.nifi.oauth2.OAuth2AccessTokenProvider;
+import org.apache.nifi.registry.flow.FlowRegistryException;
+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.web.client.api.HttpResponseEntity;
+import org.apache.nifi.web.client.api.HttpUriBuilder;
+import org.apache.nifi.web.client.api.MediaType;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Git Repository Client implementation for Azure DevOps using the REST API.
+ */
+public class AzureDevOpsRepositoryClient implements GitRepositoryClient {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(AzureDevOpsRepositoryClient.class);
+
+    private static final String API = "api-version";
+    private static final String API_VERSION = "7.2-preview";
+    private static final String AUTHORIZATION_HEADER = "Authorization";
+    private static final String CONTENT_TYPE_HEADER = "Content-Type";
+    private static final String BEARER = "Bearer ";
+
+    // Azure DevOps Git security namespace identifier used for permissions API
+    private static final String GIT_SECURITY_NAMESPACE = 
"2e9eb7ed-3c0a-47d4-87c1-0ffdd275fd87";
+    // Security token format used for repository-scoped permission checks
+    private static final String SECURITY_TOKEN_FORMAT = "repoV2/%s/%s";
+
+    // Common string values
+    private static final String EMPTY_STRING = "";
+    private static final String FORWARD_SLASH = "/";
+
+    // Path segments
+    private static final String SEGMENT_APIS = "_apis";
+    private static final String SEGMENT_PERMISSIONS = "permissions";
+    private static final String SEGMENT_GIT = "git";
+    private static final String SEGMENT_REPOSITORIES = "repositories";
+    private static final String SEGMENT_ITEMS = "items";
+    private static final String SEGMENT_REFS = "refs";
+    private static final String SEGMENT_COMMITS = "commits";
+    private static final String SEGMENT_PUSHES = "pushes";
+
+    // Permission bit for Generic Contribute
+    private static final String GENERIC_CONTRIBUTE_PERMISSION_BIT = "4";
+
+    // Query parameter names
+    private static final String PARAM_TOKENS = "tokens";
+    private static final String PARAM_FILTER = "filter";
+    private static final String PARAM_INCLUDE_CONTENT = "includeContent";
+    private static final String PARAM_FORMAT = "format";
+    private static final String PARAM_VERSION = "version";
+    private static final String PARAM_VERSION_TYPE = "versionType";
+    private static final String PARAM_PATH = "path";
+    private static final String PARAM_SCOPE_PATH = "scopePath";
+    private static final String PARAM_TOP = "$top";
+    private static final String PARAM_SEARCH_ITEM_PATH = 
"searchCriteria.itemPath";
+    private static final String PARAM_SEARCH_ITEM_VERSION = 
"searchCriteria.itemVersion.version";
+    private static final String PARAM_SEARCH_ITEM_VERSION_TYPE = 
"searchCriteria.itemVersion.versionType";
+
+    // Common parameter values
+    private static final String INCLUDE_TRUE = "true";
+    private static final String FORMAT_OCTET_STREAM = "octetStream";
+    private static final String VERSION_TYPE_COMMIT = "commit";
+    private static final String REFS_HEADS_PREFIX = "refs/heads/";
+    private static final String FILTER_HEADS_PREFIX = "heads/";
+    private static final String OBJECT_TYPE_TREE = "tree";
+    private static final String OBJECT_TYPE_BLOB = "blob";
+    private static final String JSON_FIELD_VALUE = "value";
+    private static final String JSON_FIELD_PROJECT = "project";
+    private static final String JSON_FIELD_ID = "id";
+    private static final String JSON_FIELD_NAME = "name";
+    private static final String JSON_FIELD_GIT_OBJECT_TYPE = "gitObjectType";
+    private static final String JSON_FIELD_PATH = "path";
+    private static final String JSON_FIELD_AUTHOR = "author";
+    private static final String JSON_FIELD_COMMENT = "comment";
+    private static final String JSON_FIELD_DATE = "date";
+    private static final String JSON_FIELD_COMMIT_ID = "commitId";
+    private static final String JSON_FIELD_OBJECT_ID = "objectId";
+
+    // Change request constants
+    private static final String CHANGE_TYPE_ADD = "add";
+    private static final String CHANGE_TYPE_EDIT = "edit";
+    private static final String CHANGE_TYPE_DELETE = "delete";
+    private static final String CONTENT_TYPE_BASE64 = "base64encoded";
+
+    // Common query parameter names and values
+    private static final String VERSION_DESCRIPTOR_VERSION = 
"versionDescriptor.version";
+    private static final String VERSION_DESCRIPTOR_VERSION_TYPE = 
"versionDescriptor.versionType";
+    private static final String VERSION_TYPE_BRANCH = "branch";
+    private static final String RECURSION_LEVEL = "recursionLevel";
+    private static final String RECURSION_LEVEL_ONE_LEVEL = "OneLevel";
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    private final String organization;
+    private final String project;
+    private final String repoName;
+    private final URL apiUrl;
+    private final String repoPath;
+    private final String clientId;
+    private final OAuth2AccessTokenProvider tokenProvider;
+    private WebClientServiceProvider webClient;
+
+    private final boolean canRead;
+    private final boolean canWrite;
+
+    /**
+     * Constructs an AzureDevOpsRepositoryClient with the provided 
configuration.
+     *
+     * @param builder The builder containing the configuration for the client.
+     * @throws FlowRegistryException if any required parameters are missing or 
if
+     *                               access validation fails.
+     */
+    private AzureDevOpsRepositoryClient(final Builder builder) throws 
FlowRegistryException {
+        apiUrl = Objects.requireNonNull(builder.apiUrl, "API URL required");
+        organization = Objects.requireNonNull(builder.organization, 
"Organization required");
+        project = Objects.requireNonNull(builder.project, "Project required");
+        repoName = Objects.requireNonNull(builder.repoName, "Repository Name 
required");
+        repoPath = builder.repoPath;
+        tokenProvider = Objects.requireNonNull(builder.oauthService, "OAuth2 
Access Token Provider required");
+
+        clientId = Objects.requireNonNull(builder.clientId, "Client ID is 
required");
+        webClient = Objects.requireNonNull(builder.webClient, "Web Client is 
required");
+
+        // attempt to retrieve repository information to validate access
+        final URI uri = getUriBuilder().build();
+        final JsonNode response = executeGet(uri);
+        final String projectId = 
response.get(JSON_FIELD_PROJECT).get(JSON_FIELD_ID).asText();
+        final String repoId = response.get(JSON_FIELD_ID).asText();
+
+        canRead = true;
+        canWrite = hasWriteAccess(projectId, repoId);
+
+        LOGGER.info("Created {} for clientId = [{}], repository [{}]", 
getClass().getSimpleName(), clientId, repoName);

Review Comment:
   The `clientId` seems like it could be confused with the Client ID for 
authentication. Also if it is only used for logging, is it needed?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to