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

Allow customizing visibility of the models generated from third-party protos #1778

Open
iRevive opened this issue Dec 3, 2024 · 2 comments

Comments

@iRevive
Copy link

iRevive commented Dec 3, 2024

The problem

otel4s provides a pure Scala implementation of the OpenTelemetry specification. The protocol models used by otel4s are generated from the third-party protos defined in opentelemetry-proto.

Currently, these models are generated in a public package, making them accessible on the classpath.

This poses a significant problem because opentelemetry-proto may introduce binary-breaking changes. As a result, any updates to the opentelemetry-proto can cause otel4s-sdk-exporter-proto to break binary compatibility.

https://scalapb.github.io/docs/faq/#how-do-i-mark-a-generated-case-class-private doesn't work because proto models are third-party.

The proposition

Perhaps we can extend the package-scoped options to allow customizing modifiers of a package?

import "scalapb/scalapb.proto";

package com.mypackage;

option (scalapb.options) = {
  scope: PACKAGE
  package_modifier: "private[com.mypackage]" // or "private"
};

The workaround

As a workaround, I customized the PB.generate task to override package and visibility afterward: typelevel/otel4s#860.

@thesamet
Copy link
Contributor

thesamet commented Dec 3, 2024

Hi Maksym, have you tried auxiliary options to match all messages in the package using * as a target, and make them private, using the same approach from the FAQ you linked to?

@iRevive
Copy link
Author

iRevive commented Dec 3, 2024

Hm, I never thought of this option, thanks for the suggestion!

The approach covers almost all cases. Here is the package.proto that I use:

syntax = "proto3";

package opentelemetry.proto;

import "scalapb/scalapb.proto";

option (scalapb.options) = {
  scope: PACKAGE
  aux_message_options: [
    {
      target: "*"
      options: {
        annotations: "private[proto]"
        companion_annotations: "private[proto]"
      }
    }
  ]
  aux_enum_options: [
    {
      target: "*"
      options: {
        base_annotations: "private[proto]"
      }
    }
  ]
  // not really necessary, my attempt to make 'oneof' companion private
  aux_enum_value_options: [
    {
      target: "*"
      options: {
        annotations: "private[proto]"
      }
    }
  ]
};

What is missing:

1) 'oneof' companion object remains public

Definition: https://github.com/open-telemetry/opentelemetry-proto/blob/v1.4.0/opentelemetry/proto/metrics/v1/metrics.proto#L281-L283

Generated code:

private[proto]
sealed abstract class AggregationTemporality(val value: _root_.scala.Int) extends _root_.scalapb.GeneratedEnum {
 ...
}
object AggregationTemporality extends _root_.scalapb.GeneratedEnumCompanion[AggregationTemporality] {

2) Package-specific *Proto object remains public

That's not a big deal, I guess. Generated code:

object MetricsProto extends _root_.scalapb.GeneratedFileObject {
  lazy val dependencies: Seq[_root_.scalapb.GeneratedFileObject] = Seq(
    io.opentelemetry.proto.common.v1.common.CommonProto,
    io.opentelemetry.proto.resource.v1.resource.ResourceProto
  )
  ...
}

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

No branches or pull requests

2 participants