-
Notifications
You must be signed in to change notification settings - Fork 675
fix(epics): use actual group_id for save/delete operations on nested epics #3279
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
base: main
Are you sure you want to change the base?
Conversation
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.
Pull Request Overview
This PR fixes an issue where save() and delete() operations on epics retrieved through a parent group's epic listing would fail because they used the wrong group path. The fix ensures that operations use the epic's actual group_id attribute to construct the correct API path.
- Overrides save() and delete() methods in GroupEpic to use the epic's group_id for API path construction
- Adds helper method
_epic_path()to compute the correct API path using the epic's real group - Adds comprehensive test coverage for both unit and functional scenarios
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| gitlab/v4/objects/epics.py | Implements the fix by overriding save() and delete() methods to use epic's group_id for path construction |
| tests/unit/objects/test_epics.py | Adds unit tests to verify save() and delete() operations use the correct group path |
| tests/functional/api/test_epics.py | Adds functional test demonstrating the fix works for nested epics accessed through parent groups |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
0f7065d to
3e75d60
Compare
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.
Pull Request Overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
3e75d60 to
3993fe7
Compare
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.
Pull Request Overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
3e855f3 to
27bd80c
Compare
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.
Pull Request Overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
27bd80c to
dcc9847
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3279 +/- ##
==========================================
+ Coverage 95.75% 95.76% +0.01%
==========================================
Files 98 98
Lines 6052 6068 +16
==========================================
+ Hits 5795 5811 +16
Misses 257 257
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
dcc9847 to
f420862
Compare
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.
Pull Request Overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
f420862 to
a9638ee
Compare
a9638ee to
fb4f902
Compare
fb4f902 to
8397bd0
Compare
|
FYI: This was tested and reported as working #3261 (comment) |
8397bd0 to
45a8599
Compare
…epics When an epic belonging to a subgroup is retrieved through a parent group's epic listing, save() and delete() operations would fail because they used the parent group's path instead of the epic's actual group_id. This commit overrides save() and delete() methods in GroupEpic to use the epic's group_id attribute to construct the correct API path, ensuring operations work correctly regardless of how the epic was retrieved. Also add the ability to pass a custom path using `_pg_custom_path` to the `UpdateMixin.update()` and `SaveMixin.save()` methods. This allowed the override of the `update()` method to re-use the `SaveMixin.save()` method. Closes: #3261
45a8599 to
0dd6ab1
Compare
nejch
left a comment
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.
Thanks @JohnVillalovos, looks good and that's a tricky one. Not sure about lazily fetched epics - just have a few questions there.
|
|
||
| def _epic_path(self) -> str: | ||
| """Return the API path for this epic using its real group.""" | ||
| if not hasattr(self, "group_id") or self.group_id is 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.
Can a group_id actually be none for an epic, since it's always a group resource? Or can we go with a simple try/except here?
One other thought - will this work if we get an epic with lazy=True from an arbitrary group?
| path = self._epic_path() | ||
|
|
||
| # Call SaveMixin.save() method | ||
| return super().save(_pg_custom_path=path, **kwargs) |
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.
Not sure if we should have some more generic _get_custom_path or _resolve_path helpers that would automatically get picked up by the mixins, as we already do this twice for delete/update. That way we don't need an override here (or maybe also in some other places), but I'm not sure if feasible or worth it.
| path = self.path | ||
| else: | ||
| path = f"{self.path}/{utils.EncodedId(id)}" | ||
| if "_pg_custom_path" in kwargs: |
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.
nit: pg_ always makes me think of postgres here, but maybe I've spent too much time in gitlab.rb. Also depending on the answer in the other questions, would it make sense to have this as a keyword argument instead of popping it here?
| if "_pg_custom_path" in kwargs: | |
| if "_custom_path" in kwargs: |
| } | ||
| ) | ||
|
|
||
| nested_epic = subgroup.epics.create( |
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.
Could we have this one as a fixture that yields the epic, to avoid the manual cleanup below?
Or I'm just confused by the try/finally block, maybe it was meant to test deletion even if previous things failed.
When an epic belonging to a subgroup is retrieved through a parent
group's epic listing, save() and delete() operations would fail because
they used the parent group's path instead of the epic's actual group_id.
This commit overrides save() and delete() methods in GroupEpic to use
the epic's group_id attribute to construct the correct API path, ensuring
operations work correctly regardless of how the epic was retrieved.
Also add the ability to pass a custom path using
_pg_custom_pathtothe
UpdateMixin.update()andSaveMixin.save()methods. This allowedthe override of the
update()method to re-use theSaveMixin.save()method.
Closes: #3261