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

Expose list of all artifacts, including transitive #648

Merged
merged 4 commits into from
Jan 27, 2022

Conversation

dmivankov
Copy link
Contributor

@dmivankov dmivankov commented Jan 4, 2022

And add support for :type and :classifier in defs.bzl:artifact() by internally
using strip_packaging_and_classifier_and_version. To keep support for groupId:artifactId
update strip_packaging_and_classifier_and_version implementation for that case.

To be used like

    load("@maven//:defs.bzl", "maven_artifacts")

and for example

    load("@rules_jvm_external//:defs.bzl", "artifact")
    load("@rules_jvm_external//:specs.bzl", "parse")

    all_maven_targets = [artifact(a) for a in maven_artifacts if not parse.parse_maven_coordinate(a).get("classifier", "compile") in ["sources", "native"]]

    java_export(
        name = "maven-transitive-deps-lib",
        maven_coordinates = "com.example.deps:%s:%s" % (name, "0.1"),
        visibility = ["//visibility:public"],
        runtime_deps = all_maven_targets,
    )

which makes "maven-transitive-deps-lib-pom" target available that
can be useful for other tools like security scanners and/or dependabot

dmivankov added a commit to dmivankov/rules_jvm_external that referenced this pull request Jan 4, 2022
…ependencies to some scopes

Note that using package default_visibility doesn't always work so explicit visiblity attributes are needed
bazelbuild/bazel#13681

Somewhat related to bazel-contrib#648

In combination this for example allows to create a class_name -> maven artifact resolver for
transitive dependency classes while still keeping strict visibility (making transitive dependencies
visible only to the resolve cli tool)
Copy link
Collaborator

@shs96c shs96c left a comment

Choose a reason for hiding this comment

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

I'm not sure what the utility of exposing every single maven dependency is. For code scanning, it seems like it would be more targetted to override the macros generating deployable artifacts to walk the dependencies (possibly using the has_maven_deps aspect?) Out of process tools, such as dependabot, can already do something like bazel query @maven//:all to discover all the maven artifacts.

I'm reviewing even though I don't understand the why of this PR.

coursier.bzl Outdated Show resolved Hide resolved
@dmivankov
Copy link
Contributor Author

For github dependabot script execution isn't allowed but it has support for checked in pom.xml files (and it doesn't see transitive dependencies there as different projects may potentially resolve them differently), this file can be maintained by having java_export for transitive dependencies and diff_test between checked in file and java_export pom

Second case where it can be used is writing tools that depend on both dependencies metadata and jars, with dependencies info exported into starlark one can write such tools in bazel. One example is being able to list all (classname, maven dependency) pairs.

dmivankov added a commit to dmivankov/rules_jvm_external that referenced this pull request Jan 5, 2022
…ependencies to some scopes

Note that using package default_visibility doesn't always work so explicit visiblity attributes are needed
bazelbuild/bazel#13681

Somewhat related to bazel-contrib#648

In combination this for example allows to create a class_name -> maven artifact resolver for
transitive dependency classes while still keeping strict visibility (making transitive dependencies
visible only to the resolve cli tool)
Copy link
Collaborator

@shs96c shs96c left a comment

Choose a reason for hiding this comment

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

One thing which I think our users will bump into quickly, then this is good to go. Thank you for the PR!

coursier.bzl Outdated Show resolved Hide resolved
@dmivankov
Copy link
Contributor Author

completely forgot to update this, let me maybe try exposing richer artifact information to avoid hardcoding the handling of sources and javadocs

@dmivankov dmivankov requested a review from shs96c January 17, 2022 18:49
dmivankov added a commit to dmivankov/rules_jvm_external that referenced this pull request Jan 18, 2022
…ependencies to some scopes

Note that using package default_visibility doesn't always work so explicit visiblity attributes are needed
bazelbuild/bazel#13681

Somewhat related to bazel-contrib#648

In combination this for example allows to create a class_name -> maven artifact resolver for
transitive dependency classes while still keeping strict visibility (making transitive dependencies
visible only to the resolve cli tool)
Copy link
Collaborator

@shs96c shs96c left a comment

Choose a reason for hiding this comment

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

I can see why this would be a useful feature. Thank you for explaining.

coursier.bzl Outdated
@@ -497,6 +499,17 @@ def _pinned_coursier_fetch_impl(repository_ctx):

http_files.extend(_get_jq_http_files())

http_files.extend([
"maven_artifacts = [%s]" % (",".join([
Copy link
Collaborator

Choose a reason for hiding this comment

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

This structure doesn't match the expected usage. If you tried to add these maven_artifacts to a target's runtime_deps, the build will fail, as the deps are expected to be labels and not structs.

I think there's a couple of ways of handling this:

  1. Document this clearly in the README.md and explain how people could use it.
  2. Use the maven coordinates directly, once they've been converted back from the dict they are to a string, and use the artifact macro to ensure they're loaded properly.

The first option is a lot less work, but I think the second one makes the output more usable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

one slight complication with coords is that artifact macro only works with "groupId:artifactId" and that there's strip classifier logic, need some work to extend artifact macro

for example for com.github.jnr:jffi:jar:native:1.3.1, com.github.jnr:jffi:jar:sources:1.3.1 and com.github.jnr:jffi:1.3.1 there are following targets

@maven//:com_github_jnr_jffi_native_1_3_1 // alias
@maven//:com_github_jnr_jffi_native // actual import
@maven//:com_github_jnr_jffi_jar_sources_1_3_1_extension
@maven//:com_github_jnr_jffi_jar_native_1_3_1_extension
@maven//:com_github_jnr_jffi_1_3_1_extension
@maven//:com_github_jnr_jffi_1_3_1 // alias
@maven//:com_github_jnr_jffi // import

so artifact("com.github.jnr:jffi:jar:native:1.3.1") needs to also strip jar classifier it seems

Copy link
Collaborator

Choose a reason for hiding this comment

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

The group and artifact IDs are the first two fields in the maven coordinates, which makes life a bit easier. I think you'd need to gather together all the imports, transform, and then sort, removing duplicates, and you'd be okay.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currenty I can put com.github.jnr:jffi:jar:native:1.3.1 and com.github.jnr:jffi:1.3.1 as artifacts in maven_install and then refer to them as @maven//:com_github_jnr_jffi_native and @maven//:com_github_jnr_jffi.

But there seems to be no ready-made macro yet that'd transform string "com.github.jnr:jffi:jar:native:1.3.1" to label @maven//:com_github_jnr_jffi_native

load("@rules_jvm_external//:defs.bzl", "artifact")
load("@rules_jvm_external//:specs.bzl", "parse")

s = "com.github.jnr:jffi:jar:native:1.3.1"
artifact(s) ==> @maven//:com_github_jnr_jffi # without _native part
parse.parse_maven_coordinate(s) ==> { group: "com.github.jnr", artifact: "jffi", classifier: "native", packaging: "jar", version: "1.3.1" }
artifact(parse.parse_maven_coordinate(s)) ==> still @maven//:com_github_jnr_jffi

I could decypher and replicate dict -> label conversion (aka escape(strip_packaging_and_classifier_and_version(s))), but maybe instead artifact macro should be extended to handle all potential keys (it already can accept dict, but decides to only use group and artifact)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds quite doable, but maybe there's an even better way?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Update PR with support for full string coords in artifact macro

shs96c pushed a commit that referenced this pull request Jan 19, 2022
…ependencies to some scopes (#649)

Note that using package default_visibility doesn't always work so explicit visiblity attributes are needed
bazelbuild/bazel#13681

Somewhat related to #648

In combination this for example allows to create a class_name -> maven artifact resolver for
transitive dependency classes while still keeping strict visibility (making transitive dependencies
visible only to the resolve cli tool)
return parse.parse_maven_coordinate(artifact_str)
def _ensure_version(a):
# fake :version part is due to get_simple_coord not supporting unversioned coords
return a if len(a.split(":")) > 2 else (a + ":fake_version")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ugly hack, want to reuse get_simple_coord logic with support for type and classifier, but it doesn't support unversioned artifacts, also only works on strings

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't understand why you need all of this? Is it so you can keep the one call to get_simple_coord ? Why can't this logic be put in get_simple_coord instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it can, but it may cause breaking changes to other use sites of that function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

did a quick look, looks like this should be safe so moved there now

private/rules/artifact.bzl Outdated Show resolved Hide resolved
@dmivankov dmivankov requested a review from shs96c January 21, 2022 16:18
@@ -27,7 +27,7 @@ SUPPORTED_PACKAGING_TYPES = [
"scala-jar",
]

def strip_packaging_and_classifier(coord):
def get_versioned_coord(coord):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why these name changes? Feels like the new names are not as clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

can revert renaming. New names describe the purpose and applicability (maybe even better would be get_versioned_label_name and get_simple_label_name? Didn't do that initially because the jump to labels requires an extra escape on top and there are places where escape isn't applied) and it makes it more clear why they can be reused to parse coord strings into labels, while old ones describe implementation (and applicability but for cases where we have purpose in terms of implementation / action on coord parts rather than in terms of ways to address one and the same artifact)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

reverted the rename. The only place without escape is around checking against jetify_include_list which could be shifted to operate on labels rather than coords, and it may add support for classifier to jetify_include_list, but that can be a separate PR if needed at all

Copy link
Collaborator

Choose a reason for hiding this comment

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

thanks, the diff is easier to follow without the renames.

And add support for :type and :classifier in defs.bzl:artifact() by internally
using strip_packaging_and_classifier_and_version. To keep support for groupId:artifactId
update strip_packaging_and_classifier_and_version implementation for that case.

To be used like
    load("@maven//:defs.bzl", "maven_artifacts")

and for example
    load("@rules_jvm_external//:defs.bzl", "artifact")
    load("@rules_jvm_external//:specs.bzl", "parse")

    all_maven_targets = [artifact(a) for a in maven_artifacts if not parse.parse_maven_coordinate(a).get("classifier", "compile") in ["sources", "native"]]

    java_export(
        name = "maven-transitive-deps-lib",
        maven_coordinates = "com.example.deps:%s:%s" % (name, "0.1"),
        visibility = ["//visibility:public"],
        runtime_deps = all_maven_targets,
    )

which makes "maven-transitive-deps-lib-pom" target available that
can be useful for other tools like security scanners and/or dependabot
@dmivankov
Copy link
Contributor Author

squashed and updated to remove renames and expose just the coords, making sure artifact macro now can handle coords with classifiers. Diff got smaller now

@@ -46,6 +46,10 @@ def strip_packaging_and_classifier(coord):
return ":".join(coordinates)

def strip_packaging_and_classifier_and_version(coord):
coordinates = coord.split(":")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you mind adding a test to tests/unit/coursier_utilities_test.bzl for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added a test case now

jin
jin previously requested changes Jan 26, 2022
Copy link
Collaborator

@jin jin left a comment

Choose a reason for hiding this comment

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

Given that this is a user-accessible feature, please document it in the README (or nobody will know it exists)

@dmivankov
Copy link
Contributor Author

added few new lines to readme

Copy link
Collaborator

@shs96c shs96c left a comment

Choose a reason for hiding this comment

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

Thank you for being so patient with this PR, and thank you for documenting the new feature, @dmivankov. LGTM! :)

@shs96c shs96c dismissed jin’s stale review January 27, 2022 18:49

The README has been updated as requested

@shs96c shs96c merged commit 2754341 into bazel-contrib:master Jan 27, 2022
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.

4 participants