add the internal updateGitMetadata api#15340
Conversation
albertshau
left a comment
There was a problem hiding this comment.
can you explain why we need this?
| } | ||
|
|
||
| @Override | ||
| public void updateApplicationSourceControlMeta(List<UpdateSourceControlMetaRequest> updateRequests) throws IOException { |
There was a problem hiding this comment.
I don't understand what the intent of this method is. As implemented, it looks like it is trying to create a new application version with the current app spec but with a different file hash. But why would we want to do that? The file hash is tied to the application information, if it is changing the application should also be changing.
There was a problem hiding this comment.
I have updated the implementation to update only the source_control_metadata column.
| * | ||
| * @throws IOException if scm meta update fails | ||
| */ | ||
| void updateApplicationSourceControlMeta(List<UpdateSourceControlMetaRequest> updateRequests) |
There was a problem hiding this comment.
any time a store method is added, it must be covered by new unit tests.
There was a problem hiding this comment.
Made the change to take a collection. And added unit test for the method.
| ApplicationSpecification specification); | ||
|
|
||
| /** | ||
| * updates source control meta of an application |
There was a problem hiding this comment.
Updates source control metadata for one or more applications
There was a problem hiding this comment.
Like for other batch APIs, this should clearly describe the expected behavior in relevant edge cases. For example, what is the expected behavior if one of the applications in the give collection does not exist.
There was a problem hiding this comment.
Updated the javadoc and added exception cases.
| * @throws Exception if either namespace or any of the application doesn't exist | ||
| */ | ||
| @POST | ||
| @Path("/apps/updateGitMetadata") |
There was a problem hiding this comment.
in ApplicationDetail, it is called 'sourceControlMeta'. Should update this to be consistent, updateSourceControlMeta
| List<AppUpdateGitMetaRequest> appsUpdateGitMetaRequest; | ||
|
|
||
| try { | ||
| appsUpdateGitMetaRequest = parseBody(request, listOfAppUpdateGitMetaRequestType); |
There was a problem hiding this comment.
In general, request bodies should be objects and not collections, even if it is just an object with a single collection field. This allows the API to be more extensible. For example, in the future we could add an options field or something like that.
(This is not always followed in some of the older APIs, but those are bad examples).
| throws IOException { | ||
| List<UpdateSourceControlMetaRequest> updateScmMetaRequests = new ArrayList<>(); | ||
| for (AppUpdateGitMetaRequest updateRequest : updateRequests) { | ||
| ApplicationId appId = new ApplicationId( |
There was a problem hiding this comment.
It is possible for this to throw an IllegalArgumentException for invalid application ids. Need to catch it and throw BadRequestException so that it becomes a 400.
| import io.cdap.cdap.proto.id.ApplicationId; | ||
| import java.util.Objects; | ||
|
|
||
| public class UpdateSourceControlMetaRequest { |
There was a problem hiding this comment.
in general, the classes in proto represent something in the REST APIs. This should be moved internally to app-fabric.
There was a problem hiding this comment.
moved to app-fabric. Renamed class to ApplicationSourceControlMeta.
| import java.util.Objects; | ||
|
|
||
| public class AppUpdateGitMetaRequest { | ||
| private final String appId; |
There was a problem hiding this comment.
make this consistent with ApplicationDetail.
appId -> name, fileHash -> sourceControlMeta
There was a problem hiding this comment.
done. Also renamed the class to AppUpdateSourceControlMetaRequest.
| public void updateAppScmMeta(ApplicationId appId, SourceControlMeta scmMeta) throws IOException { | ||
| ApplicationMeta existing = getApplication(appId); | ||
| if (existing == null) { | ||
| throw new IllegalArgumentException("Application " + appId + " does not exist"); |
There was a problem hiding this comment.
this shouldn't be IllegalArgumentException, ApplicaitonNotFoundException would be more specific.
Though I don't think throwing an exception is actually the behavior we want anyway. For example, if somebody deletes an application while the bulk push is happening, we probably just want to skip it instead of failing.
There was a problem hiding this comment.
Updated to throw ApplicationNotFoundException.
I think we should throw the exception here. If we do not want to fail the atomic operation, then we can simply ignore this exception and continue with the transaction.
| @Test | ||
| public void testAppMarkLatestRequestDeserialize() throws Exception { | ||
| String appUpdateGitMetadataRequest = "{\n" | ||
| + " \"appId\": \"test-application-id\"," |
There was a problem hiding this comment.
as mentioned in the other PR, this is not a useful test that we need to perform, as it is basically just testing that Gson does the right thing.
Instead, there should be unit tests covering the new logic that was added.
16a41e1 to
9f8bcd9
Compare
| /** | ||
| * Request class to update sourceControlMeta of an application. | ||
| */ | ||
| public class AppUpdateSourceControlMetaRequest { |
There was a problem hiding this comment.
Please rename to UpdateSourceControlMetaRequest
| } | ||
|
|
||
| /** | ||
| * Update scm metadata for the given apps. |
There was a problem hiding this comment.
Provide context where this will be used.
There was a problem hiding this comment.
added javadoc comment providing context on intended usage.
| public void updateSourceControlMeta(NamespaceId namespace, AppsUpdateSourceControlMetaRequest appsRequest) | ||
| throws IOException, BadRequestException, ApplicationNotFoundException { | ||
|
|
||
| List<ApplicationSourceControlMeta> updateScmMetaRequests = new ArrayList<>(); |
There was a problem hiding this comment.
nit: ApplicationSourceControlMeta class is strictly not needed. We would never need to extend this so we will be able to use a Map<ApplicationId, SourceControlMeta>
| for (AppUpdateSourceControlMetaRequest appRequest : appsRequest.getApps()) { | ||
| String appName = appRequest.getName(); | ||
| boolean isAdded = seenApps.add(appName); | ||
| if (!isAdded) { |
There was a problem hiding this comment.
single line
!(seenApps.add(appRequest.getName()))
|
|
||
| try { | ||
| ApplicationId appId = namespace.app(appName, appRequest.getAppVersion()); | ||
| SourceControlMeta scmMeta = new SourceControlMeta(appRequest.getSourceControlMeta()); |
There was a problem hiding this comment.
change SourceControlMeta in request to gitFileHash
| ); | ||
| updateScmMetaRequests.add(updateScmMetaRequest); | ||
| } catch (IllegalArgumentException | NullPointerException e) { | ||
| throw new BadRequestException("Invalid application name or version. " + e.getCause()); |
There was a problem hiding this comment.
the message should include the name , version and pass e as second parameter to the constructor.
| AppMetadataStore mds = getAppMetadataStore(context); | ||
| for (ApplicationSourceControlMeta updateRequest : updateRequests) { | ||
| ApplicationId appId = updateRequest.getAppId(); | ||
| mds.updateAppScmMeta(appId, updateRequest.getScmMeta()); |
There was a problem hiding this comment.
ignore ApplicationNotFoundException and continue. In case the app isn missing we would still want to update other app metadata
| } | ||
|
|
||
| @Test | ||
| public void testUpdateApplicationScmMeta() |
| * @throws BadRequestException when multiple filehashes are provided for an application | ||
| * @throws ApplicationNotFoundException when any of the applications is not found | ||
| */ | ||
| public void updateSourceControlMeta(NamespaceId namespace, AppsUpdateSourceControlMetaRequest appsRequest) |
There was a problem hiding this comment.
Added unit tests for success and failure cases.
| /** | ||
| * Request class to update source control meta of multiple applications. | ||
| */ | ||
| public class AppsUpdateSourceControlMetaRequest { |
There was a problem hiding this comment.
UpdateMultiSourceControlMetaReqeust
9f8bcd9 to
ce67d58
Compare
albertshau
left a comment
There was a problem hiding this comment.
looks mostly good, but the comment about update not working correctly is concerning. Can you describe how it is broken?
| appRequest.getName(), appRequest.getAppVersion() | ||
| )); | ||
| } | ||
| } catch (IllegalArgumentException | NullPointerException e) { |
There was a problem hiding this comment.
this try-catch should be only around the namespace.app() call. That way it is clear what sort of error this is happening.
| } | ||
| } catch (IllegalArgumentException | NullPointerException e) { | ||
| throw new BadRequestException( | ||
| String.format("Invalid application name (%s) or version (%s).", |
There was a problem hiding this comment.
use the exception's message new BadRequestException(e.getMessage(), e). The cause already has a more specific error message about what is wrong.
| */ | ||
| public void updateAppScmMeta(ApplicationId appId, SourceControlMeta scmMeta) | ||
| throws IOException, ApplicationNotFoundException { | ||
| final StructuredTable appSpecTable = getApplicationSpecificationTable(); |
There was a problem hiding this comment.
doesn't need to be declared final
| } | ||
|
|
||
| fields.add(Fields.stringField(StoreDefinition.AppMetadataStore.SOURCE_CONTROL_META, GSON.toJson(scmMeta))); | ||
| // upsert, because update does not seem to work correctly in the nosql implementation |
There was a problem hiding this comment.
what does this mean, what does not work correctly?
It's a big problem if the nosql implementation is broken, would mean anything else using it is broken. If it is indeed broken, please open a blocker jira and reference it in the TODO below
There was a problem hiding this comment.
Added a blocker JIRA to track this. CDAP-20853
Created the following JIRA to track this issue. The issue description can be found there. |
cc2e8e9 to
0ecb43e
Compare
albertshau
left a comment
There was a problem hiding this comment.
minor comments, otherwise lgtm.
Though it looks like the build is failing, please be sure to address any problems there.
|
|
||
| if (null == appRequest.getGitFileHash()) { | ||
| throw new BadRequestException(String.format( | ||
| "Null gitFileHash for app (name = %s, version = %s).", |
There was a problem hiding this comment.
nit: try to avoid more technical language like 'null' in user facing error messages. gitFileHash missing for app ...
There was a problem hiding this comment.
it's also fine to combine the null and empty check into one if block.
|
|
||
| SourceControlMeta scmMeta = new SourceControlMeta(appRequest.getGitFileHash()); | ||
|
|
||
| if (null != updateScmMetaRequests.put(appId, scmMeta)) { |
There was a problem hiding this comment.
nit: put the null on the other side of the equality check ... != null
a7eb8f1 to
dd9f1c1
Compare
dd9f1c1 to
505a87f
Compare
This PR adds an internal api
api/v3internal/namespaces/:namespace/apps/updateSourceControlMeta. This api takes a list of appIds (with versionIds) with gitFileHashes and updates their scm metadata in the database.JIRA: CDAP-20856