-
Notifications
You must be signed in to change notification settings - Fork 13
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 functionality to track LibraryVersion dependencies #1524
base: develop
Are you sure you want to change the base?
Conversation
24a1bee
to
8b11c8f
Compare
Github action runs on push to master or manually. |
Near the beginning of the github actions it's checking out the whole repository and then discarding it. Here are more efficient alternatives.
or
|
1cd25a7
to
d369068
Compare
the PR is ok with me, maybe Greg can review the django code. |
This commit adds: - A new M2M field on LibraryVersion to track dependencies between libraries - A GitHub workflow that generates dependency reports using boostdep - Management command to update LibraryVersion dependencies from GH artifacts - Extended GithubAPIClient to fetch artifacts from GitHub Actions - Tests for the new dependency parsing functionality - fixes boostorg#1402 The workflow analyzes each Boost release tag of the form "boost-x.x.0" to generate a dependency report which is then used to populate the dependencies field on LibraryVersion models.
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.
Nice work. Handful of small changes suggested.
core/githubhelper.py
Outdated
def get_artifacts(self, owner=None, repo=None, name=None): | ||
"""Return a list of artifacts from the GH api. | ||
|
||
Filter results by the name of the artifact by supplying name. | ||
""" | ||
owner = owner or self.owner | ||
repo = repo or self.repo_slug | ||
url = f"https://api.github.com/repos/{owner}/{repo}/actions/artifacts" |
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 think sticking to strings and tweaking the parameter name make this a bit clearer.
def get_artifacts(self, owner=None, repo=None, name=None): | |
"""Return a list of artifacts from the GH api. | |
Filter results by the name of the artifact by supplying name. | |
""" | |
owner = owner or self.owner | |
repo = repo or self.repo_slug | |
url = f"https://api.github.com/repos/{owner}/{repo}/actions/artifacts" | |
def get_artifacts(self, owner="", repo_slug="", name=""): | |
"""Return a list of artifacts from the GH api. | |
Filter results by the name of the artifact by supplying name. | |
""" | |
owner = owner or self.owner | |
repo = repo_slug or self.repo_slug | |
url = f"https://api.github.com/repos/{owner}/{repo_slug}/actions/artifacts" |
libraries/github.py
Outdated
@@ -587,3 +586,44 @@ def update_commit_author_github_data(self, obj=None, email=None, overwrite=False | |||
if gh_author["html_url"]: | |||
author.github_profile_url = gh_author["html_url"] | |||
author.save(update_fields=["avatar_url", "github_profile_url"]) | |||
|
|||
def fetch_most_recent_boost_dep_artifact_content(self, owner=None): |
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.
Is owner really optional? GH docs claim it's a required argument. If it is, probably should still use an empty string instead of None.
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.
It's not optional to github, but get_artifacts
falls back to self.owner
if the kwarg is not supplied. I can set it to an empty string by default, though.
libraries/github.py
Outdated
return | ||
return self.client.get_artifact_content(artifact["archive_download_url"]) | ||
|
||
def update_library_version_dependencies(self, owner=None, clean=False): |
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.
Same question about owner
here.
libraries/github.py
Outdated
with transaction.atomic(): | ||
if clean: | ||
library_version.dependencies.clear() | ||
library_version.dependencies.add(*dependencies) |
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 think this is a bit simpler.
with transaction.atomic(): | |
if clean: | |
library_version.dependencies.clear() | |
library_version.dependencies.add(*dependencies) | |
if clean: | |
library_version.dependencies.set(*dependencies) | |
else: | |
library_version.dependencies.add(*dependencies) |
libraries/management/commands/update_library_version_dependencies.py
Outdated
Show resolved
Hide resolved
libraries/models.py
Outdated
@@ -378,6 +378,12 @@ class LibraryVersion(models.Model): | |||
deletions = models.IntegerField(default=0) | |||
files_changed = models.IntegerField(default=0) | |||
cpp_standard_minimum = models.CharField(max_length=50, blank=True, null=True) | |||
dependencies = models.ManyToManyField( | |||
"Library", |
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.
Above, the FK to library uses libraries.Library
. Doesn't really matter, but we should probably be consistent.
libraries/tests/fixtures.py
Outdated
return """Dependencies for version boost-1.33.0 | ||
Dependencies for version boost-1.34.0 | ||
Dependencies for version boost-1.35.0 | ||
algorithm -> concept_check config detail logic numeric~conversion | ||
Dependencies for version boost-1.85.0 | ||
algorithm -> array assert bind concept_check config core | ||
numeric~conversion -> array | ||
callable_traits ->""" |
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.
You can use textwrap.dedent
to make this a bit nicer.
return """Dependencies for version boost-1.33.0 | |
Dependencies for version boost-1.34.0 | |
Dependencies for version boost-1.35.0 | |
algorithm -> concept_check config detail logic numeric~conversion | |
Dependencies for version boost-1.85.0 | |
algorithm -> array assert bind concept_check config core | |
numeric~conversion -> array | |
callable_traits ->""" | |
return dedent( | |
"""\ | |
Dependencies for version boost-1.33.0 | |
Dependencies for version boost-1.34.0 | |
Dependencies for version boost-1.35.0 | |
algorithm -> concept_check config detail logic numeric~conversion | |
Dependencies for version boost-1.85.0 | |
algorithm -> array assert bind concept_check config core | |
numeric~conversion -> array | |
callable_traits ->""" | |
) |
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.
Never used that before. Good to know.
libraries/tests/test_github.py
Outdated
assert lv.dependencies.all().count() == 5 | ||
lv = LibraryVersion.objects.get( | ||
library__key="algorithm", version__name="boost-1.85.0" | ||
) | ||
assert lv.dependencies.all().count() == 6 | ||
# callable traits is in the file but has no dependencies | ||
lv = LibraryVersion.objects.get( | ||
library__key="callable_traits", version__name="boost-1.85.0" | ||
) | ||
assert lv.dependencies.all().count() == 0 | ||
lv = LibraryVersion.objects.get( | ||
library__key="numeric/conversion", version__name="boost-1.85.0" | ||
) | ||
assert lv.dependencies.all().count() == 1 |
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.
assert lv.dependencies.all().count() == 5 | |
lv = LibraryVersion.objects.get( | |
library__key="algorithm", version__name="boost-1.85.0" | |
) | |
assert lv.dependencies.all().count() == 6 | |
# callable traits is in the file but has no dependencies | |
lv = LibraryVersion.objects.get( | |
library__key="callable_traits", version__name="boost-1.85.0" | |
) | |
assert lv.dependencies.all().count() == 0 | |
lv = LibraryVersion.objects.get( | |
library__key="numeric/conversion", version__name="boost-1.85.0" | |
) | |
assert lv.dependencies.all().count() == 1 | |
assert lv.dependencies.count() == 5 | |
lv = LibraryVersion.objects.get( | |
library__key="algorithm", version__name="boost-1.85.0" | |
) | |
assert lv.dependencies.count() == 6 | |
# callable traits is in the file but has no dependencies | |
lv = LibraryVersion.objects.get( | |
library__key="callable_traits", version__name="boost-1.85.0" | |
) | |
assert lv.dependencies.count() == 0 | |
lv = LibraryVersion.objects.get( | |
library__key="numeric/conversion", version__name="boost-1.85.0" | |
) | |
assert lv.dependencies.count() == 1 |
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
This pr adds:
The workflow analyzes each Boost release tag of the form "boost-x.x.0" to generate a dependency report which is then used to populate the dependencies M2M between LibraryVersion and Library models.