-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do not allow deprecated schemas/ontologies in imports #4391
Do not allow deprecated schemas/ontologies in imports #4391
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My guess is there's a reason why it makes more sense to do the exclusion in the resolution part, but I think it's a less straightforward system that doing it when importing from the schema. Is the resolution system another one of these features that isn't really used but adding complexity, or is this a more necessary one?
for { | ||
resourceOpt <- fetch(ref, projectRef) | ||
result <- resourceOpt.traverse(checkLatestDeprecated(ref, projectRef, _)) | ||
} yield { | ||
result match { | ||
case None => ResolverReport.failed(resolver.id, projectRef -> ResolutionFetchRejection(ref, projectRef)) -> None | ||
case Some(true) => | ||
ResolverReport.failed(resolver.id, projectRef -> ResourceIsDeprecated(ref.original, projectRef)) -> None | ||
case Some(false) => ResolverReport.success(resolver.id, projectRef) -> resourceOpt | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not quite sure how to unpick this, but feels like it could be improved? If nothing else, result
should be called isDeprecated
or similar, checkLatestDeprecated
could be more like isLatestRevisionDeprecated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I forgot to get back to this one, I will see what I can do
private def checkLatestDeprecated(resourceRef: ResourceRef, project: ProjectRef, resource: R) = | ||
resourceRef match { | ||
case _: ResourceRef.Latest => IO.pure(deprecationCheck(resource)) | ||
case _ => fetch(ResourceRef.Latest(resourceRef.original), project).map(_.exists(deprecationCheck(_))) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok so my previous comment was slightly wrong. I would argue here that this should be called something like shouldBeDisallowed
, because the current method name suggests the result is whether or not the resource is deprecated. I can see that by putting check
you're trying to communicate this, but I think maybe it needs to be taken a step further
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldDisallowDueToDeprecation
?
.downField("minCount") | ||
.as[Int] | ||
.toOption shouldEqual Some(2) | ||
expectMinCount(json, 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a nice change
_ <- deltaClient.delete[Json](s"/schemas/$project/${UrlUtils.encode(baseSchemaId)}?rev=1", Rick) { expectOk } | ||
_ <- deltaClient.post[Json](s"/schemas/$project", importingSchemaPayload, Rick) { (json, response) => | ||
response.status shouldEqual StatusCodes.BadRequest | ||
`@type`.getOption(json) shouldEqual Some("InvalidSchemaResolution") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the error not be specifically that the import was deprecated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still feels like the wrong error to receive
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is because we accumulate errors here, we can have an error because an import is deprecated and another because another one is not found at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't the user need the information in order to fix their problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The information is there, you can see it in the diff mentioning the report that is included in the payload.
I have also added a check to look for this specific error in the report
Resolution is necessary and is widely used, we rely on it to resolve remote contexts in resources, imports in schemas, there are a couple of endpoints depending on it to help people find resources, ... |
If that is the case then isn't it better to have this functionality localised to where it's used, rather than in this more general system |
for { | ||
resourceOpt <- fetch(ref, projectRef) | ||
result <- resourceOpt.traverse(runDeprecationCheck(ref, projectRef, _)) | ||
} yield { | ||
result match { | ||
// The resource has not been found in the project | ||
case None => ResolverReport.failed(resolver.id, projectRef -> ResolutionFetchRejection(ref, projectRef)) -> None | ||
// The resource exists but the deprecation check is positive so we reject it | ||
case Some(true) => | ||
ResolverReport.failed(resolver.id, projectRef -> ResourceIsDeprecated(ref.original, projectRef)) -> None | ||
// The resource has been successfully resolved | ||
case Some(false) => ResolverReport.success(resolver.id, projectRef) -> resourceOpt | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think by using meaningful variable and method names you don't really need the comments here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried and it either had a negative impact on the cross-project resolver part or it was not as clear as adding comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like this?
fetch(ref, projectRef).flatMap {
case None => IO.pure(ResolverReport.failed(resolver.id, projectRef -> ResolutionFetchRejection(ref, projectRef)) -> None)
case Some(resource) => shouldExcludeDueToDeprecation(ref, projectRef, resource)).map {
case Exclude => ResolverReport.failed(resolver.id, projectRef -> ResourceIsDeprecated(ref.original, projectRef)) -> None
case Include => ResolverReport.success(resolver.id, projectRef) -> Some(resource)
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not look really clearer and it will have an impact on the cross-project resolver side
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't fully understand the impact the change would have on cross-project resolver 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Obviously this is all a matter of opinion, but the ways in which I would see it as objectively clearer:
- No comments needed
- Boolean matching removed for clearer case objects
resourceOpt
is only used when it is Some, this is fixed- shouldExcludeDueToDeprecation is clearer than runDeprecationCheck as it is explaining the check
- Traversal is maybe not a big deal but it is a complication
I think we can move on for this PR, but the things I have mentioned are things which in general make the codebase we have difficult to understand/navigate. They are all small things by themselves, but they add up.
I'm just posting this to attempt to express how I feel about it, I think it's fine to disagree
resourceOpt <- fetch(ref, projectRef) | ||
resource <- IO.fromOption(resourceOpt)(ResolutionFetchRejection(ref, projectRef)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I preferred this previously. An option would be to make a method to hide the boilerplate
isDeprecated <- runDeprecationCheck(ref, projectRef, resource) | ||
_ <- IO.raiseWhen(isDeprecated)(ResourceIsDeprecated(ref.original, projectRef)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another instance where a method can hide the boilerplate
_ <- deltaClient.delete[Json](s"/schemas/$project/${UrlUtils.encode(baseSchemaId)}?rev=1", Rick) { expectOk } | ||
_ <- deltaClient.post[Json](s"/schemas/$project", importingSchemaPayload, Rick) { (json, response) => | ||
response.status shouldEqual StatusCodes.BadRequest | ||
`@type`.getOption(json) shouldEqual Some("InvalidSchemaResolution") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still feels like the wrong error to receive
|
If no other feature is using it right now I would say YAGNI
the latest version to check the deprecation status It's just an option. Because this feels like quite a complex solution for what on the face of it seems like a simple problem, so I think it's worth making sure we want to pay that price |
I don't see why we would exclude deprecated schemas from imports and not deprecated contexts in resources.
It is not so easy because resolvers are involved and schemas imports role is limited to accumulate imports or errors |
Fixes #1855
It is implemented at the resource resolution level as it felt weird to do it at the schema import part.
It is also not excluded that we exclude deprecated resources for other operations.