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

Include assets directly in GHRelease #977

Merged
merged 7 commits into from Nov 18, 2020

Conversation

skaldarnar
Copy link
Contributor

@skaldarnar skaldarnar commented Nov 11, 2020

Description

Resolves #528

Instead of doing a separate request to fetch the assets associated with
a release this keeps a local list of the assets that are part of the
list releases endpoint.

See https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#list-releases

The first commit c74fbbe expectedly fails at

[ERROR] Failures:
[ERROR]   LifecycleTest.testCreateRepository:39->uploadAsset:60->Assert.assertEquals:633->Assert.assertEquals:647->Assert.failNotEquals:835->Assert.fail:89 expected:<1> but was:<0>

as the call to release.getAssets() not returns the cached content instead of doing another request.

private GHAsset uploadAsset(GHRelease release) throws IOException {
GHAsset asset = release.uploadAsset(new File("LICENSE.txt"), "application/text");
assertNotNull(asset);
List<GHAsset> assets = release.getAssets();
assertEquals(1, assets.size());
assertEquals("LICENSE.txt", assets.get(0).getName());
return asset;
}

Therefore, the second commit d881bf6 brings back the previous functionality as fetchAssets(). I don't know a better name for this, and I also don't know whether this should be an option or not.

The life cycle tests use the feature that retrieving the assets from a release actually does a roundtrip to Github and sends another request. This indicates that re-purposing getAssets() to be the cached access might cause problems on consumers that potentially rely on this assumption, too.

Resolves hub4j#528

Instead of doing a separate request to fetch the assets associated with
a release this keeps a local list of the assets that are part of the
list releases endpoint.

See https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#list-releases
I don't know a better name for this, and I also don't know whether this
should be an option or not.
The life cycle tests use the feature that retrieving the assets from a
release actually does a roundtrip to Github and sends another request.
This indicates that re-purposing `getAssets()` to be the cached access
might cause problems on consumers that potentially rely on this
assumption, too.
@skaldarnar
Copy link
Contributor Author

@bitwiseman pinging you because I cannot request you as reviewer 😉

@johnoliver is this what you had in mind when opening #528 ?

Copy link
Member

@bitwiseman bitwiseman left a comment

Choose a reason for hiding this comment

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

This is a tough problem.

I think this change results in more correct behavior, but it also a breaking change in terms of the behavior of the existing method.

Someone expecting getAssets() to always return the up-to-date list of assets is going to get a very unpleasant surprise when this change goes in.

I would suggest you create a new method instead of modifying the old one (at least for now). Maybe call it getCachedAssets() and make it @Deprecated @Preview with comments explaining what is going on. Also make getAssets() @Deprecated (but not preview) with an explanation this the method is still usable but that the behavior will change in a future version.

That would unlock the behavior you want but not break existing users.

Add '@Deprecation' and '@Preview' annotations to make the changes
backwards compatible and prepare for a transition to the cached behavior
as default.
This explicitly leaves the variant for re-fetching assets under a
different name.
* @throws IOException
* the io exception
*/
public List<GHAsset> fetchAssets() throws IOException {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I left this in as I think this is a quite handy featuer to have (easily run queries to be up to date, if required). If you would rather see this removed please let me know. In that case, the test cases should also be revisitied to cover the same use case with just the new, cached behavior.

Copy link
Member

Choose a reason for hiding this comment

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

This seems reasonable. But since we're fetching, let's return a PagedIterable for more flexibility. This also means it makes sense to use the list* verb like we do on all other methods that return PagedIterable.

Suggested change
public List<GHAsset> fetchAssets() throws IOException {
public PagedIterable<GHAsset> listAssets() throws IOException {

Copy link
Member

@bitwiseman bitwiseman left a comment

Choose a reason for hiding this comment

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

This is looking great. Some additional discussion and changes. After this we should be good to go.

Thanks!

}

private void deleteAsset(GHRelease release, GHAsset asset) throws IOException {
asset.delete();
assertEquals(0, release.getAssets().size());
assertEquals(0, release.getCachedAssets().size());
Copy link
Member

Choose a reason for hiding this comment

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

This seems strange. If the asset was cached in the release before deletion, it should be there after was well - that cache shouldn't change. Perhaps add an assert that the asset if present in getCachedAssets() before deletion?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The confusing part here might be that we're still dealing with the very first GHRelease from this test - even before we actually created an asset for it.

I'll take another look at the tests and see if I can add something in addition to make this clearer

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I get it now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried to figure out how this whole wiremock setup works - and gave up 😕 To be able to add an assertion like the one you mentioned I'd need to re-fetch the intermediate state of the release, e.g.,

// test that asset upload works
GHAsset asset = uploadAsset(release);
// get new "snapshot" of the release with cached asset
GHRelease releaseWithAsset = repository.getReleases().get(0);
// update the asset, check before and after with the new snapshot
updateAsset(releaseWithAsset, asset);
// repeat same pattern for 'delete'

However, it looks like the wiremocks do not account for additional calls to repository.getReleases().get(0) I suppose, at least they obviously don't return the new state of the release...

If I should change something in these tests I'd appreciate your help... 🙄

Copy link
Member

Choose a reason for hiding this comment

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

I need to make it easier to re-record tests, but in the meanwhile here's the instructions:
https://github.com/hub4j/github-api/blob/master/CONTRIBUTING.md#generating-a-new-snapshot

The instructions could be better too. 😢

Copy link
Member

Choose a reason for hiding this comment

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

But it is okay to leave this as it is.

* @throws IOException
* the io exception
*/
public List<GHAsset> fetchAssets() throws IOException {
Copy link
Member

Choose a reason for hiding this comment

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

This seems reasonable. But since we're fetching, let's return a PagedIterable for more flexibility. This also means it makes sense to use the list* verb like we do on all other methods that return PagedIterable.

Suggested change
public List<GHAsset> fetchAssets() throws IOException {
public PagedIterable<GHAsset> listAssets() throws IOException {

*/
@Deprecated
@Preview
public List<GHAsset> getCachedAssets() {
Copy link
Member

Choose a reason for hiding this comment

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

API design question for you: Thinking about it a bit more, what do you think about using a bare property names for field access? I don't think this needs changing for this change, but I'm thinking about what this should look like in v2.

    public List<GHAsset> assets() {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would really like this kind of simplified naming 👍 🤓

public List<GHAsset> getAssets() throws IOException {
Requester builder = owner.root.createRequest();
return fetchAssets();
Copy link
Member

Choose a reason for hiding this comment

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

Given we change the name and return type of fetchAssets():

Suggested change
return fetchAssets();
return listAssets().toList();

@@ -45,18 +45,20 @@ public void testCreateRepository() throws IOException {

private void updateAsset(GHRelease release, GHAsset asset) throws IOException {
asset.setLabel("test label");
assertEquals("test label", release.getAssets().get(0).getLabel());
assertEquals("test label", release.fetchAssets().get(0).getLabel());
Copy link
Member

Choose a reason for hiding this comment

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

Keep the test pointing to the deprecated method since it wraps the new method and we want to show the behavior hasn't changed.

Suggested change
assertEquals("test label", release.fetchAssets().get(0).getLabel());
assertEquals("test label", release.getAssets().get(0).getLabel());

@bitwiseman bitwiseman merged commit 78f533b into hub4j:master Nov 18, 2020
@skaldarnar skaldarnar deleted the feat/528-ghrelease-assets branch November 22, 2023 19:28
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.

assets on GHRelease
2 participants