Skip to content

Commit f91896a

Browse files
authored
Allow non-default targets (#187)
1 parent 01e8116 commit f91896a

File tree

22 files changed

+203
-125
lines changed

22 files changed

+203
-125
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
The set of scripts in this repository provides a solution for:
1111
- Generating pom.xml files for jars built by Bazel (typically ```java_library``` or ```java_binary``` rules)
1212
- Uploading the pom.xmls and jars to a Maven Artifact Repository such as Nexus (or installing them into the local Maven Repository at ~/.m2/repository)
13+
- Handling the grouping of related jars into a "library", similar to a multi-module Maven project: all jars that are part of the same library are uploaded together
14+
- Crawling library references and uploading those that have changed since they were last uploaded to Nexus
1315

1416
pomgen does not run as part of the Bazel build - therefore Bazel BUILD files can remain free of pom.xml related metadata.
1517

@@ -54,6 +56,7 @@ See [this doc](docs/change_detection.md) for more information on change detectio
5456

5557
Please see the [hello-world example](examples/hello-world/README.md) to see how pomgen works.
5658

59+
5760
## External Dependencies
5861

5962
- Bazel, ideally through [bazelisk](https://github.com/bazelbuild/bazelisk)
@@ -176,6 +179,7 @@ Please see [more information about transitives versioning](docs/ci.md#using-a-di
176179

177180
See [this example](examples/dep-overrides).
178181

182+
179183
## CI setup
180184

181185
[This document](docs/ci.md) goes over the CI setup.

crawl/buildpom.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class MavenArtifactDef(object):
2121
Represents an instance of a maven_artifact rule defined in BUILD.pom file.
2222
Information from the BUILD.pom.released file is added, if that file exists.
2323
24+
2425
==== Read out of the BUILD.pom file ====
2526
2627
group_id: the maven artifact groupId of the bazel package.
@@ -64,6 +65,7 @@ class MavenArtifactDef(object):
6465
version_increment_strategy_name: specifies how this artifacts version should
6566
be incremented.
6667
68+
6769
==== Read out of the optional BUILD.pom.released file ====
6870
6971
released_version: the previously released version to Nexus
@@ -72,19 +74,22 @@ class MavenArtifactDef(object):
7274
previously released to Nexus
7375
7476
77+
7578
===== Internal attributes (never specified by the user) ====
7679
7780
deps: additional targets this package depends on; list of Bazel labels.
7881
For example: deps = ["//projects/libs/servicelibs/srpc/srpc-thrift-svc-runtime"]
7982
80-
Only used by tests.
83+
The deps attribute is only used by tests.
84+
85+
bazel_package: the bazel package the BUILD (and MVN-INF/) files live in
8186
82-
bazel_package: the bazel package the BUILD.pom file lives in
87+
bazel_target: the bazel target that builds this artifact
8388
84-
library_path: the path to the root directory of the library this
85-
monorepo package is part of
89+
library_path: the path to the root directory of the library this artifact
90+
is part of
8691
87-
requires_release: whether this monorepo package should be released (to Nexus
92+
requires_release: whether this artifact should be released (to Nexus
8893
or local Maven repository)
8994
9095
release_reason: the reason for releasing this artifact
@@ -93,6 +98,7 @@ class MavenArtifactDef(object):
9398
BUILD.pom file, the content of the pom.xml.released file
9499
=====
95100
101+
96102
Implementation notes:
97103
- properties are kept read-only whenever possible
98104
- the constructor provides default values for easier instantiation
@@ -115,6 +121,7 @@ def __init__(self,
115121
released_version=None,
116122
released_artifact_hash=None,
117123
bazel_package=None,
124+
bazel_target=None,
118125
library_path=None,
119126
requires_release=None,
120127
released_pom_content=None):
@@ -133,6 +140,7 @@ def __init__(self,
133140
self._released_version = released_version
134141
self._released_artifact_hash = released_artifact_hash
135142
self._bazel_package = bazel_package
143+
self._bazel_target = bazel_target
136144
self._library_path = library_path
137145
self._requires_release = requires_release
138146
self._release_reason = None
@@ -206,6 +214,10 @@ def released_artifact_hash(self, value):
206214
def bazel_package(self):
207215
return self._bazel_package
208216

217+
@property
218+
def bazel_target(self):
219+
return self._bazel_target
220+
209221
@property
210222
def library_path(self):
211223
return self._library_path
@@ -279,6 +291,7 @@ def parse_maven_artifact_def(root_path, package):
279291
additional_change_detected_packages=ma_attrs.get("additional_change_detected_packages", []),
280292
gen_dependency_management_pom=ma_attrs.get("generate_dependency_management_pom", False),
281293
jar_path=ma_attrs.get("jar_path", None),
294+
bazel_target=ma_attrs.get("target_name", None),
282295
deps=ma_attrs.get("deps", []))
283296

284297
template_path = ma_attrs.get("pom_template_file", None)
@@ -348,6 +361,7 @@ def _augment_art_def_values(user_art_def, rel_art_def, bazel_package,
348361
gen_dependency_management_pom=False if user_art_def.gen_dependency_management_pom is None else user_art_def.gen_dependency_management_pom,
349362
jar_path=None if user_art_def.jar_path is None else os.path.normpath(os.path.join(bazel_package, mdfiles.MD_DIR_NAME, user_art_def.jar_path)),
350363
deps=user_art_def.deps,
364+
bazel_target=user_art_def.bazel_target if user_art_def.bazel_target is not None else os.path.basename(bazel_package),
351365
released_version=rel_art_def.version if rel_art_def is not None else None,
352366
released_artifact_hash=rel_art_def.artifact_hash if rel_art_def is not None else None,
353367
bazel_package=bazel_package,

crawl/crawler.py

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,11 @@ def _get_deps_transitive_closure_for_library(self, library_path,
220220
# other, but these references are not guaranteed)
221221
artifacts = self.library_to_artifact[library_path]
222222
for art_def in artifacts:
223-
all_deps.add(dependency.new_dep_from_maven_artifact_def(art_def, bazel_target=None))
224-
223+
all_deps.add(dependency.new_dep_from_maven_artifact_def(art_def))
225224
return all_deps
226225

227226
def _get_crawled_packages_as_deps(self):
228-
deps = [dependency.new_dep_from_maven_artifact_def(art_def, bazel_target=None) for art_def in self.package_to_artifact.values()]
227+
deps = [dependency.new_dep_from_maven_artifact_def(art_def) for art_def in self.package_to_artifact.values()]
229228
deps = set(self._filter_non_artifact_referencing_deps(deps))
230229
return deps
231230

@@ -510,7 +509,10 @@ def _crawl(self, package, dep, parent_node, follow_references):
510509
511510
Returns a Node instance for the crawled package.
512511
"""
513-
target_key = self._get_target_key(package, dep)
512+
artifact_def = self.workspace.parse_maven_artifact_def(package)
513+
if artifact_def is None:
514+
raise Exception("No artifact defined at package %s" % package)
515+
target_key = self._get_target_key(package, dep, artifact_def)
514516
if target_key in self.target_to_node:
515517
# if we have already processed this target, we can re-use the
516518
# children we discovered previously
@@ -532,13 +534,7 @@ def _crawl(self, package, dep, parent_node, follow_references):
532534
else:
533535
if self.verbose:
534536
logger.info("Processing [%s]" % target_key)
535-
artifact_def = self.workspace.parse_maven_artifact_def(package)
536-
537-
if artifact_def is None:
538-
raise Exception("No artifact defined at package %s" % package)
539537

540-
self._validate_default_target_dep(parent_node, dep, artifact_def)
541-
542538
self.package_to_artifact[package] = artifact_def
543539
self.library_to_artifact[artifact_def.library_path].append(artifact_def)
544540
pomgen = self._get_pom_generator(artifact_def, dep)
@@ -563,20 +559,6 @@ def _crawl(self, package, dep, parent_node, follow_references):
563559
self._store_if_leafnode(node)
564560
return node
565561

566-
def _validate_default_target_dep(self, parent_node, dep, artifact_def):
567-
if dep is not None:
568-
if artifact_def.pom_generation_mode.produces_artifact:
569-
# if the current bazel target produces an artifact
570-
# (pom/jar that goes to Nexus), validate that the BUILD
571-
# file pointing at this target uses the default bazel
572-
# package target
573-
# this is a current pomgen requirement:
574-
# 1 bazel package produces one artifact, named after the
575-
# bazel package
576-
dflt_package_name = os.path.basename(artifact_def.bazel_package)
577-
if dep.bazel_target != dflt_package_name:
578-
raise Exception("Non default-package references are only supported to non-artifact producing packages: [%s] can only reference [%s], [%s:%s] is not allowed" % (parent_node.artifact_def.bazel_package, artifact_def.bazel_package, artifact_def.bazel_package, dep.bazel_target))
579-
580562
def _get_pom_generator(self, artifact_def, dep):
581563
if dep is None:
582564
# make a real dependency instance here so we can pass it along
@@ -587,12 +569,15 @@ def _get_pom_generator(self, artifact_def, dep):
587569
dep)
588570

589571
@classmethod
590-
def _get_target_key(clazz, package, dep):
572+
def _get_target_key(clazz, package, dep, artifact_def=None):
591573
if dep is None:
592-
target = os.path.basename(package)
574+
# initial bootstrap - we start a bazel package and we don't
575+
# have a dep pointing here
576+
assert artifact_def is not None
577+
target = artifact_def.bazel_target
593578
else:
594579
target = dep.bazel_target
595-
assert target is not None, "Target is None for dep %s" % dep
580+
assert target is not None, "Target is None for package %s" % package
596581
return "%s:%s" % (package, target)
597582

598583
def _store_if_leafnode(self, node):

crawl/dependency.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,9 @@ def new_dep_from_maven_art_str(maven_artifact_str, name):
314314

315315

316316
def new_dep_from_maven_artifact_def(artifact_def, bazel_target=None):
317-
if bazel_target is not None:
318-
assert len(bazel_target) > 0, "bazel target must not be empty for artifact def %s" % artifact_def.bazel_package
317+
if bazel_target is None:
318+
bazel_target = artifact_def.bazel_target
319+
assert bazel_target is not None
319320
return MonorepoDependency(artifact_def, bazel_target)
320321

321322

crawl/pomparser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,5 +213,5 @@ def _import_lxml():
213213
return etree
214214
except ImportError as ex:
215215
print("Module lxml is not installed, please execute the following in your environment:")
216-
print("pip install --user lxml")
216+
print("pip3 install --user lxml")
217217
return None

crawl/workspace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def _parse_dep_label(self, dep_label):
126126
raise Exception("Unknown external dependency - please make sure all maven install json files have been registered with pomgen (by setting maven_install_paths in the pomgen config file): [%s]" % dep_label)
127127
return self._label_to_ext_dep[dep_label]
128128
elif dep_label.startswith("//"):
129-
# monorepo src ref:
129+
# src ref:
130130
package_path = dep_label[2:] # remove leading "//"
131131
target_name = None
132132
i = package_path.rfind(":")

docs/mdfiles.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ maven_artifact_update(
2222
)
2323
```
2424

25+
2526
#### Required Attributes
2627

2728
##### maven_artifact.group_id
@@ -50,8 +51,13 @@ Given a current version of `1.2.3`, the `major`, `minor`, and `patch` incrementi
5051

5152
Given a current version of `20230605.1`, the `calver` incrementing strategy would produce `<todaydate>.1` (or `<todaydate>.2` if the current version is already `<todaydate>.1`).
5253

54+
5355
#### Optional Attributes
5456

57+
##### maven_artifact.target_name
58+
59+
The name of the bazel target that builds the jar artifact pomgen will be processing. Defaults to the [default target](https://bazel.build/concepts/labels) of the bazel package (aka the target that has the same name as the directory the BUILD file, that defines the target, lives in).
60+
5561
##### maven_artifact.change_detection
5662

5763
Controls whether change detection should be enabled for this artifact. If set to `False`, this artifact will always be marked as needing to be released (and a new pom will always be generated).
@@ -85,6 +91,7 @@ Default value: `None`
8591

8692
See the `java_import` [example](../examples/java-import).
8793

94+
8895
### LIBRARY.root (required)
8996

9097
The LIBRARY.root file is a marker file that is currently empty. It groups together multiple artifacts, defined by BUILD.pom files, into a single "library". All artifacts that belong to a single library are processed (installed/uploaded) together. Change detection also operates at the library level. If a single artifact in a library has changed, then all artifacts in the library are marked as needing to be released.

examples/compile-only-dependencies/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# Compilation time only dependencies should not be evaluated by pomgen
22

3-
43
There are some dependencies that are needed only at compilation time, for example Lombok. To ensure compile-time only dependencies are not included at runtime, Bazel has the `neverlink` attribute, which can be added to `java_library` rules.
54
Typically compile-time only dependencies won't have a `BUILD.pom` file, so they have to be ignored by `pomgen`.
65

examples/dependency-management/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ This examples shows how pomgen can optionally generate a dependencyManagement "c
44

55
The dependency management pom contains a `<dependencyManagement>` section with the transitive closure of all dependencies of the artifact it was generated for. It uses the `artifact_id` specified in the BUILD.pom file, suffixed with `.depmanagement`.
66

7+
78
### Try this example
89

910
From the root of the repository:

examples/hello-world/README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55

66
In the Maven world, a typical project setup consists of a top level pom.xml file with multiple modules in subdirectories. Each module produces a Maven Artifact (typically a jar or a pom.xml).
77

8-
The pomgen terminology for a top level project with modules is a "library". Subdirectories of the library (the modules) are Bazel Packages that each produce a Maven Artifact (jar or pom). pomgen processes all modules that are part of a library together.
8+
The pomgen terminology for a top level project with modules is a `library`. Subdirectories of the library (the modules) are Bazel Packages that each produce a Maven Artifact (jar or pom). pomgen processes all modules that are part of a library together.
99

1010
This example has 3 libraries. A library is defined by the presence of a [LIBRARY.root](healthyfoods/MVN-INF/LIBRARY.root) marker file.
1111

12-
A Bazel Package that produces a Maven Artifact must have a [BUILD.pom](healthyfoods/fruit-api/MVN-INF/BUILD.pom) file that defines Maven specific metadata. Note that the `java_library` target that builds the jar Maven Artifact must be the default target, ie it must have the same name as the directory its BUILD file lives in.
12+
A Bazel Package that produces a Maven Artifact must have a [BUILD.pom](healthyfoods/fruit-api/MVN-INF/BUILD.pom) file that defines Maven specific metadata.
1313

14-
The libraries in this example are, and reference each other in this order:
14+
The `java_library` target that builds the jar Maven Artifact is typically the default target, ie it the target that the same name as the directory its BUILD file lives in. If the target is not the default target, its name must be explicitly specified in the BUILD.pom file using the `maven_artifact.target_name` attribute.
15+
16+
The libraries in this example reference each other in this order:
1517
- [juicer](juicer)
1618
- [wintervegetables](wintervegetables)
1719
- [healthyfoods](healthyfoods)
@@ -67,7 +69,7 @@ The command above specifies:
6769
- The **library** to generate poms for: `examples/hello-world/juicer`
6870

6971

70-
pomgen follows refernces between libraries; since `juicer` depends on 2 other libraries `healthyfoods` and `wintervegerables`, pomgen generated pom.xml files for all 3 libraries, ie for all modules that are part of those libraries. Usually this is the right behavior, but if there a lot of upstream libraries, it may be desirable in some cases to not follow library references. This can be accomplished by setting `-i` (ignore references) flag:
72+
pomgen follows references between libraries; since `juicer` depends on 2 other libraries `healthyfoods` and `wintervegerables`, pomgen generated pom.xml files for all 3 libraries, ie for all modules that are part of those libraries. Usually this is the right behavior, but if there a lot of upstream libraries, it may be desirable in some cases to not follow library references. This can be accomplished by setting `-i` (ignore references) flag:
7173

7274
```
7375
bazel run @pomgen//maven -- -a pomgen -l examples/hello-world/juicer -i

examples/hello-world/juicer/BUILD

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
java_library(
2-
name = "juicer",
2+
name = "juicer_lib",
33
srcs = glob(["src/main/java/**/*.java"]),
44
deps = ["//examples/hello-world/healthyfoods/fruit-api",
55
"//examples/hello-world/healthyfoods/vegetable-api",
6-
"//examples/hello-world/wintervegetables",
6+
"//examples/hello-world/wintervegetables:wintervegetables_lib2",
77
"@maven//:com_google_guava_guava",
88
]
99
)
1010

1111
java_binary(
1212
name = "make-juice",
13-
runtime_deps = [":juicer"],
13+
runtime_deps = [":juicer_lib"],
1414
main_class = "com.pomgen.example.Main",
1515
)

examples/hello-world/juicer/MVN-INF/BUILD.pom

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ maven_artifact(
33
artifact_id = "juicer",
44
version = "10.0.0-qual1-SNAPSHOT",
55
pom_generation_mode = "dynamic",
6+
target_name = "juicer_lib",
67
)
78

89
maven_artifact_update(

examples/hello-world/wintervegetables/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
java_library(
2-
name = "wintervegetables",
2+
name = "wintervegetables_lib2",
33
srcs = glob(["src/main/java/**/*.java"]),
44
deps = ["//examples/hello-world/healthyfoods/vegetable-api"],
55
visibility = ["//examples/hello-world/juicer:__subpackages__"],

examples/hello-world/wintervegetables/MVN-INF/BUILD.pom

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ maven_artifact(
33
artifact_id = "wintervegetables",
44
version = "20200416.1-SNAPSHOT",
55
pom_generation_mode = "dynamic",
6+
target_name = "wintervegetables_lib2",
67
)
78

89
maven_artifact_update(

0 commit comments

Comments
 (0)