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

Support for Bill Of Materials #59

Open
afloarea opened this issue Feb 1, 2025 · 4 comments
Open

Support for Bill Of Materials #59

afloarea opened this issue Feb 1, 2025 · 4 comments

Comments

@afloarea
Copy link

afloarea commented Feb 1, 2025

Summary

Maven supports the idea of a Bill of Materials (BOMs) that hold versions for dependencies.

For example:

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.vertx</groupId>
                <artifactId>vertx-stack-depchain</artifactId>
                <version>${vertx.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

Then dependencies can be declared without version:

        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-core</artifactId>
        </dependency>

        <dependency> <!--Optional dependency of vertx-core-->
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

This allows for upgrading the dependencies in the BOM all at once with a single version change of the BOM.

Proposal

Add support for BOMs in bld

For example:

public class BldProjectBuild extends Project {
    public BldProjectBuild() {
        pkg = "com.example";
        name = "example";
        mainClass = "com.example.Main";
        version = version(0, 1, 0);
        javaRelease = 21;

        repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES);

        BillOfMaterials bom = BillOfMaterials.of("io.vertx", "vertx-stack-depchain", version(4, 5, 12));

        scope(compile)
                .include(dependency("io.vertx", "vertx-core", bom))
                .include(dependency("com.fasterxml.jackson.core", "jackson-databind", bom));
    }

    public static void main(String[] args) {
        new BldProjectBuild().start(args);
    }
}

Of course, this is just an example, maybe there is better syntax for this or maybe there is a better approach altogether. Please let me know what you think.

@ethauvin
Copy link
Contributor

ethauvin commented Feb 1, 2025

@afloarea Thanks for bringing this up. There is some limited support for BOM in bld, but not to extend you are describing.

How would your example really differ from:

bom = version(4, 5, 12);
scope(compile)
    .include(dependency("io.vertx", "vertx-core", bom))
    .include(dependency("com.fasterxml.jackson.core", "jackson-databind"));

Gradle also introduces the concept of platform:

dependencies {
    implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
    implementation("org.jetbrains.kotlin:kotlin-stdlib")
}

Which ensures that all Kotlin dependencies in your project use the same version specified in the BOM.

@afloarea
Copy link
Author

afloarea commented Feb 2, 2025

@ethauvin Thank you for the quick reply and thank you in advance for your patience with this (too long) post.

First, please let me try to highlight the difference.

In the maven example (with the vertx-stack-depchain), with vertx.version set to 4.5.12:

  • Looking at vertx-stack-depchain:4.5.12, I see in the list com.fasterxml.jackson.core:jackson-core:2.16.1 and com.fasterxml.jackson.core:jackson-databind:2.16.1
  • I see that vertx-core has a compile dependency on jackson-core: and an optional dependency on jackson-databind
  • If I do not include jackson-databind in the pom.xml and run mvn dependency:tree I can see that I only have jackson-core:2.16.1
  • If I include the jackson-databind entry in the pom.xml and run mvn dependency:tree again, I can see that now I also have jackson-databind:2.16.1

Moving to bld:
If I use

var bom = version(4, 5, 12);
scope(compile)
    .include(dependency("io.vertx", "vertx-core", bom));

and run ./bld dependency-tree I can see jackson-core:2.16.1, just like maven.
However, if I use

var bom = version(4, 5, 12);
scope(compile)
    .include(dependency("io.vertx", "vertx-core", bom))
    .include(dependency("com.fasterxml.jackson.core", "jackson-databind"));

and run ./bld dependency-tree again (after ./bld download purge) I will see:

...
└─ com.fasterxml.jackson.core:jackson-databind
   ├─ com.fasterxml.jackson.core:jackson-annotations:2.18.2
   └─ com.fasterxml.jackson.core:jackson-core:2.18.2

So, no version in the output for jackson-databind and (also confirmed by looking in the lib/compile directory) I now have jackson-core and jackson-databind with version 2.18.2 rather than 2.16.1. This time it is different than what I get with maven.


When I created the ticket, I was thinking of having a way to explicitly configure (in some form or another) that the dependencies should have the version declared in a BOM, rather than have the build system guess what the user wants/needs.

As such, I made up the BillOfMaterials bom = BillOfMaterials.of("io.vertx", "vertx-stack-depchain", version(4, 5, 12)); which would be passed to the dependency declaration/method call, so that it can grab the version from the bom somehow. In the case of jackson-databind it would grab the version 2.16.1 from the bom.

Having a bom:1.0.0 with

  • depA:1.0.0
  • depB:1.0.0
  • depC:1.1.2
    would also allow upgrading to bom:2.0.0 with
  • depA:1.1.4
  • depB:1.5.0
  • depC:2.0.0
    by just changing the bom version

Maybe the platform way gradle does it would be fitting for bld too, I don't know. At the same time I don't know how gradle handles the case where you have multiple BOMs that have conflicting versions of a dependency (probably picks the lower version between the 2?). Probably a niche case but I think it's not impossible.

Maybe passing the bom as the version explicitly would eliminate guesswork for the build tool? Or maybe I am just overthinking this 😅 and the way gradle does it is better choice.

I am not a build tool or dependency management specialist, so I may be very wrong with all of this. If something I mentioned doesn't make sense or is flat out wrong, please let me know.

Thanks again for your patience.

@ethauvin
Copy link
Contributor

ethauvin commented Feb 4, 2025

@gbevin What do you think of the proposed syntax?

It does deal with all the case scenarios I can think of, but I'm not sure how that would integrate with bld's internals.

@gbevin
Copy link
Contributor

gbevin commented Feb 9, 2025

Thanks for the suggestion @afloarea, I'm thinking about what the best way would be to support this.

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

3 participants