Skip to content
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

Emit events for all known types #127

Merged
merged 46 commits into from
Mar 31, 2023
Merged

Conversation

dmdashenkov
Copy link
Contributor

@dmdashenkov dmdashenkov commented Mar 17, 2023

In this PR we enable ProtoData plugin authors to listen to Protobuf compiler events that describe types from dependencies.

Previously, events like TypeEntered were only emitted for Proto definitions from within the module that ProtoData is processing. This is good for many cases, since this removes the need to check whether or not any code has to be generated based on a given event. However, this limited the users to only the types defined in the module. There was no way to know about a Proto message type from outside the module.

Now, we introduce a new DepdendencyDiscovered event and a ProtobufDependencyFile view. The two new types allow ProtoData plugin authors to generate code with awareness of the module's dependencies.

@dmdashenkov dmdashenkov self-assigned this Mar 17, 2023
@codecov
Copy link

codecov bot commented Mar 17, 2023

Codecov Report

Merging #127 (ff3ab1e) into master (23108f9) will increase coverage by 2.38%.
The diff coverage is 94.17%.

Additional details and impacted files
@@             Coverage Diff              @@
##             master     #127      +/-   ##
============================================
+ Coverage     79.35%   81.73%   +2.38%     
- Complexity      236      240       +4     
============================================
  Files            73       79       +6     
  Lines          1889     1993     +104     
  Branches        140      146       +6     
============================================
+ Hits           1499     1629     +130     
+ Misses          335      313      -22     
+ Partials         55       51       -4     

@dmdashenkov dmdashenkov marked this pull request as ready for review March 17, 2023 11:25
@dmdashenkov
Copy link
Contributor Author

@armiol, @alexander-yevsyukov, PTAL.

This is a small yet consequential change set. Let's further discuss it a video call if necessary.

Copy link
Collaborator

@alexander-yevsyukov alexander-yevsyukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my comments. In general, I think that the generation_requested flag approach should be discussed.

report_paths: '**/build/test-results/test/TEST-*.xml'
require_tests: true # will fail workflow if test reports not found

# See: https://github.com/marketplace/actions/junit-report-action
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we revert these changes please? Separation of test reports was needed some time ago when investigating build failures at CI.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmdashenkov I think this comment still stands.

@@ -68,13 +68,15 @@ internal class EnumCompilerEvents(
EnumEntered.newBuilder()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider using Kotlin DSL for Protobuf. It should be already available here. I've just tried it in another branch and it worked for me.

Copy link
Collaborator

@armiol armiol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmdashenkov I am now requesting changes, so that you could re-request from me, once this PR is ready. Alexander is off for a while, so it will be just me.

@dmdashenkov dmdashenkov requested a review from armiol March 24, 2023 15:59
@dmdashenkov
Copy link
Contributor Author

@armiol, PTAL.

armiol
armiol previously requested changes Mar 24, 2023
Copy link
Collaborator

@armiol armiol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmdashenkov please see my comments.

report_paths: '**/build/test-results/test/TEST-*.xml'
require_tests: true # will fail workflow if test reports not found

# See: https://github.com/marketplace/actions/junit-report-action
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmdashenkov I think this comment still stands.

@@ -264,3 +265,15 @@ message RpcExited {

RpcName rpc = 3;
}

// Emitted when a Protobuf dependency file is discovered.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this about discovering an import in our code? I am not sure what do you mean by "discovered".

// Normally, no code should be generated for dependencies. However, they can be used for additional
// info when generating code for the module's own types.
//
message DependencyDiscovered {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be more precise with this name, so that Java- and Proto-level dependencies could be distinguished.

Copy link
Contributor Author

@dmdashenkov dmdashenkov Mar 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the doc somewhat. I'd like to avoid adding the Proto prefix because:

  • we only work with Protobuf, no Java or JS or other dependency is ever considered in ProtoData (not talking about the Gradle compiler here, only ProtoData proper);
  • this is one of a series of events such as TypeEntered, OptionDiscovered, etc., which do not specify the language either.

}

/**
* Assigns the field type and cardinality (`map`/`list`/`oneof_name`/`single`) to the receiver
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this, in fact, copying the field type and the cardinality? If so, maybe we could get rid of this "assign" term which feels a bit over-used in our domain?

* Assigns the field type and cardinality (`map`/`list`/`oneof_name`/`single`) to the receiver
* builder.
*
* @return the receiver for method chaining.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, in Kotlin we still don't put periods in @return statement descriptions.

/**
* Produces a sequence by walking through all the nested message definitions staring with `type`.
*
* @param type the message definition which may contain nested message definition to walk though
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"through"

*
* The event reflects all the definitions from the file.
*/
internal fun toDependencyEvent(fileDescriptor: Descriptors.FileDescriptor) =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about discoverDependencies(fileDescriptor: Descriptors.FileDescriptor)?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about discoverDependencies(fd: FileDescriptor)? :)

import com.google.protobuf.Descriptors.MethodDescriptor
import com.google.protobuf.Descriptors.OneofDescriptor
import com.google.protobuf.Descriptors.ServiceDescriptor
import io.spine.protodata.Doc
import io.spine.string.trimWhitespace
import io.spine.util.interlaced

/**
* Documentation contained in a Protobuf file.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given its description, I don't really understand why such a generic thing is now in .backend.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of the word .backend either.

This is the top-level package name for the :compiler module. :compiler serves as main implementation module for ProtoData.

Previously, Documentation, CompilerEvents, and other types where placed in the :api module in ...event package. However, it's not clear that those components belong in the :api module. Moving them to :compiler is logical since this is clearly an implementation detail (hence the internal modifier). The change of the package is a mere consequence.

I could repackage said components into ...backend.event, but I don't see much value in that right now. Would love to hear what you think.

@@ -149,10 +154,10 @@ private constructor(private val value: List<Int>) {
*/
fun fromMessage(descriptor: Descriptor): LocationPath {
val numbers = mutableListOf<Int>()
numbers.add(FileDescriptorProto.MESSAGE_TYPE_FIELD_NUMBER)
numbers.add(DescriptorProtos.FileDescriptorProto.MESSAGE_TYPE_FIELD_NUMBER)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a lot of such changes in this PR. Don't you think it's less convenient to address the types and their members by specifying a "full" (so to speak) name, rather than stripping some common parts by having them "statically" imported?

import io.spine.protodata.OneofGroup
import io.spine.protodata.TypeName
import io.spine.protodata.event.FieldEntered
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the events apparently are still in io.spine.protodata.event package, I don't understand why MessageCompilerEvents isn't.

I have the same question regarding all the similar cases. Maybe, we should discuss the idea of re-packaging things into .backend as a whole. Because right now I don't understand the goal.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmdashenkov, we do need event package so that Javadocs, KDocs, and source code JARs are easier to understand. Please do have events coming under the event package.

* A type URL contains the type URL prefix and the qualified name of the type separated by
* the slash (`/`) symbol. See the docs of `google.protobuf.Any.type_url` for more info.
*/
public fun typeUrl(): String? {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the return value can really be null, please document when such a case can occur.

Copy link
Collaborator

@alexander-yevsyukov alexander-yevsyukov Mar 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProtoDeclarationName has a similar method that returns non-nullable String. How these two types are different in that regards?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, that was a mistake. Fixed it.

doc = documentation.forField(this@buildField)
[email protected] = [email protected]
[email protected] = declaringType
copyTypeAndCardinality(this@buildField)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please extract this@buildField into a variable (e.g. fieldDescr, or thisField). This way you'd have fewer “dogs” around.

Copy link
Collaborator

@alexander-yevsyukov alexander-yevsyukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my additional comments.

declaredIn = declaringType
[email protected] = [email protected]
orderOfDeclaration = index
doc = documentation.forEnumConstant(this@buildConstant)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly to the comment above, extracting this@buildConstant into a val in this block could improve the readability.

@dmdashenkov
Copy link
Contributor Author

@alexander-yevsyukov, @armiol, PTAL again.

Copy link
Collaborator

@alexander-yevsyukov alexander-yevsyukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my comments. Almost there.

* A type URL contains the type URL prefix and the qualified name of the type separated by
* the slash (`/`) symbol. See the docs of `google.protobuf.Any.type_url` for more info.
*/
public fun typeUrl(): String {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we have it as another property rather than a function? Just curious, how you see it.

One reason I can think of is to have shorter names in Java code. But we aim to Kotlin anyway, and we always can have @JvmName defined, should we want to.

@@ -183,8 +201,8 @@ class CompilerEventsSpec {

event.option.name shouldBe "idempotency_level"
event.option.value.unpackGuessingType() shouldBe enumValue {
name = IdempotencyLevel.NO_SIDE_EFFECTS.name
number = IdempotencyLevel.NO_SIDE_EFFECTS_VALUE
name = DescriptorProtos.MethodOptions.IdempotencyLevel.NO_SIDE_EFFECTS.name
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we import MethodOptions, please?

@dmdashenkov
Copy link
Contributor Author

@alexander-yevsyukov, PTAL again.

Copy link
Collaborator

@alexander-yevsyukov alexander-yevsyukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dmdashenkov dmdashenkov enabled auto-merge March 31, 2023 08:26
@dmdashenkov dmdashenkov dismissed armiol’s stale review March 31, 2023 09:10

Since we've discussed this PR in a call already.

@dmdashenkov dmdashenkov added this pull request to the merge queue Mar 31, 2023
Merged via the queue into master with commit 621a33a Mar 31, 2023
@armiol armiol deleted the emit-events-for-all-known-types branch June 13, 2023 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants