Skip to content
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

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

brianjp93
Copy link
Collaborator

@brianjp93 brianjp93 commented Dec 6, 2024

This pr 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
  • A daily task to check for the boostdep artifact and update dependencies
  • Extended GithubAPIClient to fetch artifacts from GitHub Actions
  • Tests for the new dependency parsing functionality
  • fixes Save dependencies for each LibraryVersion #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 M2M between LibraryVersion and Library models.

@brianjp93 brianjp93 force-pushed the 1402-deps branch 3 times, most recently from 24a1bee to 8b11c8f Compare December 6, 2024 00:29
@brianjp93
Copy link
Collaborator Author

Github action runs on push to master or manually.

@brianjp93 brianjp93 marked this pull request as ready for review December 6, 2024 00:36
@sdarwin
Copy link
Collaborator

sdarwin commented Dec 6, 2024

Near the beginning of the github actions it's checking out the whole repository and then discarding it. Here are more efficient alternatives.

  • Simply download the file in a one-liner without checking out the repo. (if this works it seems preferable).

curl -OL https://github.com/${GITHUB_REPOSITORY}/blob/${GITHUB_SHA}/.github/workflows/scripts/get_deps.sh?raw=true

or

# Fetch only a single file
- uses: actions/checkout@v4
  with:
    sparse-checkout: |
      .github/workflows/scripts/get_deps.sh
    sparse-checkout-cone-mode: false

@brianjp93 brianjp93 force-pushed the 1402-deps branch 3 times, most recently from 1cd25a7 to d369068 Compare December 6, 2024 17:14
@sdarwin
Copy link
Collaborator

sdarwin commented Dec 6, 2024

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.
Copy link
Collaborator

@GregKaleka GregKaleka left a 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.

Comment on lines 495 to 502
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"
Copy link
Collaborator

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.

Suggested change
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"

@@ -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):
Copy link
Collaborator

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.

Copy link
Collaborator Author

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 Show resolved Hide resolved
return
return self.client.get_artifact_content(artifact["archive_download_url"])

def update_library_version_dependencies(self, owner=None, clean=False):
Copy link
Collaborator

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.

Comment on lines 619 to 622
with transaction.atomic():
if clean:
library_version.dependencies.clear()
library_version.dependencies.add(*dependencies)
Copy link
Collaborator

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.

Suggested change
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)

@@ -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",
Copy link
Collaborator

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.

Comment on lines 237 to 244
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 ->"""
Copy link
Collaborator

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.

Suggested change
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 ->"""
)

Copy link
Collaborator Author

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.

Comment on lines 375 to 388
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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

libraries/utils.py Show resolved Hide resolved
Copy link
Collaborator

@GregKaleka GregKaleka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Save dependencies for each LibraryVersion
4 participants