dependency-tree-diff
dependency-tree-diff copied to clipboard
Support multiple configurations in one diff
Allow gradlew :module:dependencies > deps.txt to be the input to the program.
Also includes some fixes from #11 and #12, but I think those will get merged first.
Solution
Originally the "dependency list" was created by looking between +--- and an empty line.
I've extended this to look for the starting token +---, then peek before to find the configuration name (and sometimes description). Then create a map of (configuration, diff), and produce a nice output.
Note: all expected.txts had to change because it now outputs which configuration is being diffed, even when there's only one.
Examples where configurations and dependencies change
(gradlew :dependencies on this project with different version of Gradle and Kotlin):
- gradle66-kotlin14.txt
- gradle742-kotlin14.txt
- gradle742-kotlin15.txt
- gradle742-kotlin16.txt
- gradle742-kotlin17.txt
The unit tests include gradle742-kotlin14.txt and gradle742-kotlin15.txt diff (configuration-differences) as well as a diff of one of my projects when updating Dagger which affects compile, runtime and kapt classpaths (multiple-configurations).
Rebased on #12 and #11 merges, now clean, ready for review/rejection :)
Yeah I'm a bit hesitant about adding this. The reason we didn't do this initially was because there's far too much noise/duplication in the output. In an Android project or a Kotlin multiplatform project you can get upwards of 30 or 40 configurations which rarely are unique.
What's the motivation to diff them all?
Simple: I want to see an overall change, even if it's long. At the moment I'm diffing two trees by hand, and I want to adopt this tool, but, without support for multiple configurations, I can't get equivalent use.
Here's what I have so far, based on this PR to add multiple support: https://github.com/TWiStErRob/net.twisterrob.cinema/runs/7052429575 This check run fails the build if the deps change, and I can see a ready-made diff, which I can approve via a few clicks. (This last bit is just for fun to practice and test what GHA can be used for.)
Argument 1: changing a dependency won't affect just one configuration
Let's take the above Dagger as the first example: if I diff'd the runtime classpath as you suggest in the readme, I would get this:
Looks all good, but looking at all configurations reveals that it actually changed kapt classpaths a lot, which, if I had multiple annotation processors could cause problems.
Another example for the same is changing test-only dependencies, e.g. Robolectric / Espresso, or prod+test dependencies like androidx fragment + fragment-testing.
To discover issues in all the above cases, I (and everyone else in the world using this) would need to know exactly which configurations are affected for each of the dependency changes and manually diff each one of them.
Argument 2: multiple modules is already adding enough overhead
Having a multi-module project is normal and dependencies in each module change. What I did in this cinema project is a bit overkill, diffing all modules, but you can easily imagine having multiple entry points in one project (android, desktop, backend monorepo). Creating diffs for each module is already complicated, imagine having to use the tree-diff tool to generate 7-8 diffs per module for specific relevant configurations (release, debug, variant) x (kapt, kaptTest, test, compileOnly, runtime).
Argument 3: sheer dev laziness
How much simpler it is to run gradlew :app:dependencies than using --configuration= 😅. I would imagine most devs have problems with the syntax of Gradle's command line, or don't know what configurations are, or know but don't care. So catering for more developer use cases helps the community.
Argument 4: compatibility and DX
In addition to the above use case I think it's simply a DX improvement to handle the standard output gradlew dependencies can produce, not just a specific case, but all of them (similar to #12, but the other way around 😄). Allowing to diff the whole output also helps to use this in automation detecting any kind of change in the tree, and outputting it in a nice way, like I did in the above CI job.
Another example for 1) I'm migrating from buildSrc to libs and that's a syntax change, so there shouldn't be any deps diff. At this point I need full diff, which of course could be done just with a normal diff, but your tree diff is way better. GitHub Check run discovering I made a mistake somewhere: https://github.com/TWiStErRob/net.twisterrob.cinema/pull/145/checks?check_run_id=7059856668
In order to maintain behavioral compatibility, if there's only a single configuration lets omit the header with its name.
Otherwise this seems fine to include.
Can I add a flag to include it?
If there's only one why is it needed?
If you want to rebase and remove the header for single configuration scenarios I'm still open to this. Going to do a release with a bugfix first, however.
Ugh, this slipped off my to-do list :) Will do the rebase this week.