Repository: pantsbuild/pants

Issue:
Scheduling workunit renders for JVM processes
`Scheduling: Run Spoon analysis against Java source` renders for JVM import extraction, but shouldn't. The "Scheduling" workunit is intended to render only briefly before we attempt to acquire the local execution semaphore.

It's likely that this has something to do with `nailgun` usage... but this isn't the first time we've experienced an issue with this rendering, and we should likely just remove its description entirely.


Discussion:

Resolving patch:
diff --git a/src/python/pants/backend/java/dependency_inference/java_parser.py b/src/python/pants/backend/java/dependency_inference/java_parser.py
--- a/src/python/pants/backend/java/dependency_inference/java_parser.py
+++ b/src/python/pants/backend/java/dependency_inference/java_parser.py
@@ -124,7 +124,7 @@ async def analyze_java_source_dependencies(
             use_nailgun=tool_digest,
             append_only_caches=jdk_setup.append_only_caches,
             env=jdk_setup.env,
-            description="Run Spoon analysis against Java source",
+            description=f"Analyzing {source_files.files[0]}",
             level=LogLevel.DEBUG,
         ),
     )
diff --git a/src/python/pants/jvm/resolve/coursier_fetch.py b/src/python/pants/jvm/resolve/coursier_fetch.py
--- a/src/python/pants/jvm/resolve/coursier_fetch.py
+++ b/src/python/pants/jvm/resolve/coursier_fetch.py
@@ -40,6 +40,7 @@
 from pants.jvm.resolve.key import CoursierResolveKey
 from pants.jvm.subsystems import JvmSubsystem
 from pants.jvm.target_types import (
+    JvmArtifact,
     JvmArtifactArtifactField,
     JvmArtifactFieldSet,
     JvmArtifactGroupField,
@@ -233,25 +234,35 @@ class CoursierResolvedLockfile:
 
     entries: tuple[CoursierLockfileEntry, ...]
 
+    @classmethod
+    def _coordinate_not_found(cls, key: CoursierResolveKey, coord: Coordinate) -> CoursierError:
+        # TODO: After fixing https://github.com/pantsbuild/pants/issues/13496, coordinate matches
+        # should become exact, and this error message will capture all cases of stale lockfiles.
+        return CoursierError(
+            f"{coord} was not present in resolve `{key.name}` at `{key.path}`.\n"
+            f"If you have recently added new `{JvmArtifact.alias}` targets, you might need to "
+            f"update your lockfile by running `coursier-resolve --names={key.name}`."
+        )
+
     def direct_dependencies(
-        self, coord: Coordinate
+        self, key: CoursierResolveKey, coord: Coordinate
     ) -> tuple[CoursierLockfileEntry, tuple[CoursierLockfileEntry, ...]]:
         """Return the entry for the given Coordinate, and for its direct dependencies."""
         entries = {(i.coord.group, i.coord.artifact): i for i in self.entries}
         entry = entries.get((coord.group, coord.artifact))
         if entry is None:
-            raise CoursierError(f"{coord} was not present in {self}")
+            raise self._coordinate_not_found(key, coord)
 
         return (entry, tuple(entries[(i.group, i.artifact)] for i in entry.direct_dependencies))
 
     def dependencies(
-        self, coord: Coordinate
+        self, key: CoursierResolveKey, coord: Coordinate
     ) -> tuple[CoursierLockfileEntry, tuple[CoursierLockfileEntry, ...]]:
         """Return the entry for the given Coordinate, and for its transitive dependencies."""
         entries = {(i.coord.group, i.coord.artifact): i for i in self.entries}
         entry = entries.get((coord.group, coord.artifact))
         if entry is None:
-            raise CoursierError(f"{coord} was not present in {self}")
+            raise self._coordinate_not_found(key, coord)
 
         return (entry, tuple(entries[(i.group, i.artifact)] for i in entry.dependencies))
 
@@ -390,7 +401,7 @@ async def fetch_with_coursier(
     # transitive dependencies, etc.
     assert len(request.component.members) == 1, "JvmArtifact does not have dependencies."
     root_entry, transitive_entries = lockfile.dependencies(
-        Coordinate.from_jvm_artifact_target(request.component.representative)
+        request.resolve, Coordinate.from_jvm_artifact_target(request.component.representative)
     )
 
     classpath_entries = await MultiGet(


Test patch:
diff --git a/src/python/pants/jvm/resolve/coursier_fetch_filter_test.py b/src/python/pants/jvm/resolve/coursier_fetch_filter_test.py
--- a/src/python/pants/jvm/resolve/coursier_fetch_filter_test.py
+++ b/src/python/pants/jvm/resolve/coursier_fetch_filter_test.py
@@ -8,12 +8,14 @@
 
 import pytest
 
+from pants.engine.fs import EMPTY_DIGEST
 from pants.jvm.resolve.coursier_fetch import (
     Coordinate,
     Coordinates,
     CoursierLockfileEntry,
     CoursierResolvedLockfile,
 )
+from pants.jvm.resolve.key import CoursierResolveKey
 
 coord1 = Coordinate("test", "art1", "1.0.0")
 coord2 = Coordinate("test", "art2", "1.0.0")
@@ -85,8 +87,9 @@ def test_filter_transitive_includes_transitive_deps(lockfile: CoursierResolvedLo
 
 
 def filter(coordinate, lockfile, transitive) -> Sequence[Coordinate]:
+    key = CoursierResolveKey("example", "example.json", EMPTY_DIGEST)
     if transitive:
-        root, deps = lockfile.dependencies(coordinate)
+        root, deps = lockfile.dependencies(key, coordinate)
     else:
-        root, deps = lockfile.direct_dependencies(coordinate)
+        root, deps = lockfile.direct_dependencies(key, coordinate)
     return list(i.coord for i in (root, *deps))