-
Notifications
You must be signed in to change notification settings - Fork 293
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
Fixes #24679 - Sorting repos Red Hat repos page #7690
Conversation
Issues: #24679 |
architecture_groups.each do |group, repo_sets| | ||
sorted_architecture_groups[group] = repo_sets.sort_by do |repo| | ||
release_ver = repo[:substitutions][:releasever] | ||
release_ver.split('.').map(&:to_i) |
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 looking at this line and thinking about what it does - which is give us something like [5, 11] if we are looking at a 5.11 release version. Ruby sort_by is able to understand sorting across multiple elements in an array such as this.
I also observed that there is quite a bit of code here to perform this search including a regular expression which I personally like to avoid unless necessary. With that in mind and also thinking about sorting across multiple values with sort_by I wrote this:
results = repos.sort_by do |repo|
major_minor = repo[:substitutions][:releasever].split('.').map(&:to_i)
minor = major_minor[1].nil? ? 1 : major_minor[1]
[repo[:substitutions][:basearch], major_minor[0], minor]
end
I also gave results.reverse
to collection
It seems to work but you might want to check the page for examples which are missing data such as the basearch.
|
||
get :available_repositories, params: { product_id: @product.id, id: @content_id } | ||
|
||
correct_version_sort = [{"substitutions" => {"releasever" => "5.11", "basearch" => "i386"}, "path" => ""}, |
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.
How is the result affected if you add '7Workstation' in addition to existing '7Server' to x86_64 arch?
@@ -41,7 +41,6 @@ def show | |||
def available_repositories | |||
scan_cdn = sync_task(::Actions::Katello::RepositorySet::ScanCdn, @product, @product_content.content.cp_content_id) | |||
repos = scan_cdn.output[:results] | |||
|
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.
Let's put the empty line back. I think judicious use of newlines makes code more readable within our rubocop guidelines of course!
5dc9c26
to
46de3f7
Compare
New commit pushed. |
major, minor = repo[:substitutions][:releasever].nil? ? 1000.1000 : repo[:substitutions][:releasever].split('.').map(&:to_i) | ||
major = major == 0 ? 1000 : major | ||
minor = minor.nil? ? 1000 : minor | ||
repo[:substitutions][:basearch] = repo[:substitutions][:basearch].nil? ? "" : repo[:substitutions][:basearch] |
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.
In this line you're setting basearch to an empty string where it would have been nil in the response. That's probably not what you wanted to do! Let's change this to preserve (not modify) the basearch on the repo itself.
@@ -52,11 +52,21 @@ def available_repositories | |||
end | |||
end | |||
|
|||
sorted_groups = repos.sort_by do |repo| |
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.
Naming nitpick! This variable has the word 'groups' in it. Personally, I would expect it to be a Hash structure of some kind with the keys representing the groups for example. There is no actual "grouping" here in terms of the data structure returned. What about sorted_repos
?
content_id.must_equal @content_id | ||
end | ||
|
||
task.expects(:output).at_least_once.returns(results: [{:substitutions => {:releasever => "5.10", :basearch => "i386"}, :path => ""}, |
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 see that your mocked data and your expected data are identical - just in a different order. Can you come up with a way to eliminate the duplication and achieve the same result? I think the shuffle
method will be handy here: https://ruby-doc.org/core-2.2.0/Array.html#method-i-shuffle
@@ -103,6 +103,51 @@ def test_available_repositories | |||
assert_response :success | |||
end | |||
|
|||
def test_available_repo_sort | |||
task = assert_sync_task ::Actions::Katello::RepositorySet::ScanCdn do |product, content_id| |
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.
The primary concern of this test is sorting, so I think we are OK to remove any assertions against this task especially since they are identical to a pre-existing test.
It can be rewritten:
task = assert_sync_task ::Actions::Katello::RepositorySet::ScanCdn
@@ -52,11 +52,21 @@ def available_repositories | |||
end | |||
end | |||
|
|||
sorted_groups = repos.sort_by do |repo| | |||
major, minor = repo[:substitutions][:releasever].nil? ? 1000.1000 : repo[:substitutions][:releasever].split('.').map(&:to_i) | |||
major = major == 0 ? 1000 : major |
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.
What's the significance of checking for 0 here instead of nil? check like minor version?
4fb69b4
to
adff7ba
Compare
Newest commits pushed. |
{ :substitutions => { :releasever => version, :basearch => arch }, :path => path }.with_indifferent_access | ||
} | ||
|
||
expected_sort = [repo_set.call(version: nil, arch: "x86_64", path: ""), |
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.
since your lambda function provides a default empty path you don't need to set it on your expected sort list
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'm not sure what you are saying here. :)
Maybe that I can just drop the expected_sort altogether? What would hold my final sorted list?
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 mean you can change your expected values to ex: repo_set.call(version: nil, arch: "x86_64")
and omit the path since your lambda function is giving ""
by default. I think that'd be preferred here since your test case isn't concerned with the value in path
at all
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 see, when you said path, I wasn't thinking of the actual value, "path", but of something else. :)
adff7ba
to
9e520dc
Compare
New (and final?) commit pushed. :) |
[test katello] |
9b507b8
to
f6850be
Compare
@johnsonm325 this looks great to me, and I verified that it works. Since I had a bit of a hand in this I think we need an ACK from another developer as well. For any other devs looking: the API changes were the first attempt and we found that we needed to fix the UI as well, so the API changes are not really relevant. However, since it improves the default sort of the API I am OK with leaving those changes in. |
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.
ACK
Before final ACK, I wanted to discuss best way to test here. This appears to be the best place to test here: https://github.com/akofink/katello/blob/1b2585759b5ed27063f353db038bd06f65944899/webpack/scenes/RedHatRepositories/components/__tests__/RepositorySetRepository.test.js Would we be building upon this test, or adding to it to check for proper order? |
} | ||
|
||
if (repo1.arch === repo2.arch) { // arch is the same | ||
// look at major, minor |
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.
oh, one ask. these comments are pretty self-explanatory & think they can be removed
@@ -52,11 +52,21 @@ def available_repositories | |||
end | |||
end | |||
|
|||
sorted_repos = repos.sort_by do |repo| | |||
major, minor = repo[:substitutions][:releasever].nil? ? 1000.1000 : repo[:substitutions][:releasever].split('.').map(&:to_i) |
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 might have meant [1000, 1000] here
Testing wise it looks like new test file is needed for the JS component. There is one for RepositorySetRepository, but we are here in RepositorySetRepositories |
@@ -28,7 +28,36 @@ class RepositorySetRepositories extends Component { | |||
} | |||
|
|||
const availableRepos = [...data.repositories.filter(({ enabled }) => !enabled)] |
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.
@johnpmitsch any advice on how to test availableRepos
? Since it's effectively private my first thought would be to test the output of render
itself - but want to make sure that is correct since this test relies on external data that we would mock out.
Ultimately we are wanting to test that the RepositorySetRepository components are in the correct order once rendered .. something like:
<RepositorySetRepositories>
<RepositorySetRepository ...>
<RepositorySetRepository ...>
<RepositorySetRepository ...>
</RepositorySetRepository>
Does shallow
make this an impossiblity?
Would it be easier to move availableRepos
out of render
and test it as an ordinary method?
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.
A few thoughts:
This feels like something that should be outside of render.
I'm thinking something like this method declared in the class (all untested):
sortedRepos = () => {
const { data } = this.props;
return [...data.repositories.filter(({ enabled }) => !enabled)]
.sort((repo1, repo2) => {
//sort logic
}
}
Then in render() do this:
const availableRepos = this.sortedRepos().map(repo => (
<RepositorySetRepository key={repo.arch + repo.releasever} type={type} {...repo} />
));
const repoMessage = (data.repositories.length > 0 && availableRepos.length === 0 ?
__('All available architectures for this repo are enabled.') : __('No repositories available.'));
return (
<Spinner loading={data.loading}>
{availableRepos.length ? availableRepos : <div>{repoMessage}</div>}
</Spinner>
);
Then you can test the sortedRepos() function by using the snapshot instance. You may have to modify it to take arguments rather than read from props. There is an example here of testing this method
@@ -52,11 +52,21 @@ def available_repositories | |||
end | |||
end | |||
|
|||
sorted_repos = repos.sort_by do |repo| | |||
major, minor = repo[:substitutions][:releasever].nil? ? 1000.1000 : repo[:substitutions][:releasever].split('.').map(&:to_i) |
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.
Sorry to add this late in the review, but is Gem::Version
of any use here? We use this in other places when comparing versions
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.
No problem! I don't see any current examples in our code, but looking at what the class does I don't think it'd be a great fit since we are looking at things like architectures and versions that are not just things like '7.3' but also things like '7Server'. Not to say that it couldn't be made to work, but feels like we wouldn't get much value. Open to be shown otherwise though :)
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.
Sounds fair to me. I guess we don't use it in Katello, but I know its used in foreman-maintain since it deals with package versions, maybe that is where I was thinking of. Carry on :)
f6850be
to
18ad81b
Compare
I know exactly what went wrong with my rubocop offense, but I could not figure out the npm lint error: http://ci.theforeman.org/blue/organizations/jenkins/katello-pr-test/detail/katello-pr-test/3183/pipeline/62 Any clues? |
@@ -16,6 +16,39 @@ class RepositorySetRepositories extends Component { | |||
} | |||
} | |||
|
|||
sortedRepos = (repos) => { |
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 fixed the lint this way:
sortedRepos = repos => [...repos.filter(({ enabled }) => !enabled)]
.sort((repo1, repo2) => {
const repo1YStream = yStream(repo1.releasever || '');
const repo2YStream = yStream(repo2.releasever || '');
I ran eslint locally with --fix
./node_modules/.bin/eslint webpack/scenes/RedHatRepositories/components/RepositorySetRepositories.js --fix
18ad81b
to
bb56eca
Compare
[test katello] |
I'm getting a lint error here that I'm not getting locally. Not sure what I'm missing, but I'm not seeing the issue in the file it's referencing. @johnpmitsch Do you mind giving the final ack here since you have had eyes on the fix? This is a GA bug, so needs a merge this morning. Thanks! |
|
||
expectedIndices.forEach((expected, i) => { | ||
expect(result[i]).toEqual(repos[expected]); | ||
}); |
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 know there were no tests before, but we really should have a snapshot comparison for any component. here is an example
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.
Does that need to be in the form of toJson(shallowWrapper)? Or can we put the correct order of repos in the snapshot and then expect(result).toMatchSnapshot(); ?
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.
this is a separate test outside of the repo sorting testing, snapshots are a rendered component, which is then used as comparison on any future tests so you can see what has changed in the actual render when you refactor/change anything
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.
Something like what I've added in my new commit?
Linting issue is unrelated to your PR and is being fixed here |
bb56eca
to
4863ad3
Compare
expect(result[i]).toEqual(repos[expected]); | ||
}); | ||
|
||
expect(toJson(shallowWrapper)).toMatchSnapshot(); |
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 really should be in its own its
block, which means you would have to split out shallowRender
too. If you want to keep it in this its
block, just adjust the description to sorts repos correctly and renders
or something like that.
4863ad3
to
2f4be21
Compare
Ok, this should hopefully be the final run. Thanks for all of the feedback. |
[test katello] |
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.
ACK from a code perspective
@johnpmitsch @jturel Sweet! I think this is ready to be merged then? |
Description of problem: Sorting of available minor version repos is not consistent. To test this bug, upload a manifest and expand the the products on the Red Hat Repositories page.
Example: When we look for "Red Hat Enterprise Linux 7 Server (RPMs)" repos we see "x86_64 7Server" as a first entry. Whereas when we look for "Red Hat Enterprise Linux 6 Server (RPMs)" repos then we see "x86_64 6Server" as the last entry and the sorting is like:
i386 6.1
x86_64 6.1
x86_64 6.10 <<<< After 6.1 we should see 6.2 instead of 6.10
i386 6.10
i386 6.2
x86_64 6.2
i386 6.3
...
...
...
x86_64 6Server
i386 6Server
6Server or 7Server are base repositories and these are most commonly used repos so those should be listed as a first entry.
Solution:
Repos are now grouped by architecture (i386, ia64, x86_64), and then ordered by base repositories first (Server, Workstation, etc.) and then in descending order (7.11, 7.10, 7.9, etc.).