-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add support for relationship
attribute in DependencySubmission
payload
#12768
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
Add support for relationship
attribute in DependencySubmission
payload
#12768
Conversation
aa28e82
to
8782ea9
Compare
…? Could we use it to track transitive dependencies?
This commit: - backs out previous WIP that added `dependency_file` to `Dependabot::Dependency` - introduces `Dependabot::DependencyFile#dependencies` list Now, for the bundler ecosystem at least, DependencyFiles included in DependencySnapshots will be aware of their Dependabot::Dependency objects – and DependencySubmission payloads can accurately reflect the contents of the specified manifests.
2e98f11
to
f02ba8a
Compare
36eed25
to
5c56412
Compare
5c56412
to
ea7d193
Compare
In order to create DependencySubmission payloads, we must keep track of dependencies on a per-DependencyFile level, and those dependency objects must know whether they are direct dependencies (`#top_level?`) and whether they are usined in `production?`. First we tried faking `Dependency#requirements` objects but this broke a number of tests; somewhere deep within Dependabot there is an assumption that lockfiles do not produce dependencies with requirements. Instead of trying to fix the tests, here is a different approach: - Instead of faking `requirements` objects, we instead directly supply the `top_level?` boolean at instantiation, i.e. before, top_level was a synonym for `requirements.any?` and now it is not. Hopefully this turns out to be a simpler modification going forward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏻 On this approach, I'm nervous about changing the contract of top_level?
but I also don't love having two methods meaning slightly different things in different contexts.
Instead of overriding `top_level?`, which on inspection is a leaky abstraction – it's often used elsewhere as a synonym for "has requirements" – here we introduce our own method that only means "this dependency has a direct relationship".
Co-authored-by: Barry Gordon <[email protected]>
relationship
attribute in DependencySubmission
payloadrelationship
attribute in DependencySubmission
payload
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I lack the real power of approval, but this LGTM
gemfile = payload[:manifests].fetch("/Gemfile") | ||
expect(gemfile[:name]).to eq("/Gemfile") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to ask why we were adding a /
here, but on checking the API docs, this is just an arbitrary name. Comparing with a real world payload, I note people doing esoteric things like:
project-a/pom.xml > project-a
expect(capybara[:scope]).to eq("development") | ||
# the lockfile should be reporting 4 direct dependencies and 24 indirect ones | ||
expect(lockfile[:resolved].values.count { |dep| dep[:relationship] == "direct" }).to eq(4) | ||
expect(lockfile[:resolved].values.count { |dep| dep[:relationship] == "indirect" }).to eq(24) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
Huh, I do not lack the real power of approval 😅 - I'll set it to neutral until a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I approve in a non-binding way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
We've been kind of... working around DependencySet for a while. If you think introducing a new data structure that doesn't smoosh dependencies into a set would be easier, feel free and we can work that back into Dependabot's update code at some point.
IIRC @phillmv and I talked about this lightly where we'd ideally replace |
What are you trying to accomplish?
Per https://github.com/github/dependency-graph/issues/7121,
[for those of you who do not work at GitHub, the above link describes an effort we're undergoing to refactor technical debt and start using dependabot-core to parse dependencies for our dependency graph service.]
This PR is a follow up on #12734 . Now that we can generate payloads, the next step is to fill out the remaining attributes that the Dependency Submission API expects.
This PR then:
Dependency#direct?
as a bit of state we can track when parsing dependenciesAnything you want to highlight for special attention from reviewers?
In order to get here there was a meandering path. The first step involved realizing that the
DependencySet
class squashes all of theDependencies
it has parsed and combines them into a flat list; this means that we could not produce an accurate list of thelockfile
's dependencies because the overlapping ones would be assigned to thegemfile
.In order to get around this now associate dependencies directly with their
DependencyFile
via a new associationDependencyFile#dependencies
.In order to start tracking whether a dependency is direct or transitive, we need to keep track of this within the
Dependency
class. At first we tried addingrequirements
objects to direct dependencies parsed from thelockfile
but this caused weird test failures deep within Dependabot, so we skipped that. We eventually settled on adding a newDependency#direct?
method that either mimicstop_level?
or can be set directly via ivar on initialize.How will you know you've accomplished your goal?
All tests pass & we deploy it and see it send requests to our API.
Checklist