-
Notifications
You must be signed in to change notification settings - Fork 10
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
Refactor add on auto client #54
Refactor add on auto client #54
Conversation
if (srcid == -1 || srcid == nil) | ||
# revert back to the unexpanded URL to have the original URL | ||
# in the saved /etc/zypp/repos.d file | ||
Pkg.SourceChangeUrl(srcid, media) |
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.
Reading the source code of Pkg.SourceChangeUrl
, I think that this line was doing nothing. Am I right?
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.
Yes, that was wrong.
end | ||
|
||
reject |
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.
why not having something like this in block?
next false unless add_on.fetch("media_url", "").empty?
log.error "Missing <media_url> value in the #{index}. add-on-product definition"
# abort import/installation
return false unless skip_add_on_and_continue?(index)
true
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, nice!
Thank you!
Pkg.SourceChangeUrl(srcid, media) | ||
|
||
if Ops.get_boolean(prod, "ask_on_error", false) | ||
prod["ask_on_error"] = Popup.ContinueCancel( |
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 avoided to overwrite the original value of ask_on_error
property, but I have no clear if there is some reason to do it.
"</li>" | ||
end | ||
|
||
["<ul>", formatted_add_on, "</ul>"].flatten.join("\n") |
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 write it without flatten like ["<ul>", *formatted_add_on, "</ul>"].join("\n")
def reset | ||
AddOnProduct.add_on_products = [] | ||
|
||
{} |
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 needed. Reset return value should not be used see https://github.com/yast/yast-yast2/blob/0d1f6001e99734c8da163d78c04bf53b029ba8c4/library/general/src/lib/installation/auto_client.rb#L114
false | ||
) | ||
|
||
UI.CloseDialog |
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 looks wrong for me Opening with Wizard.CreateDialog and closing with UI.CloseDialog. Why not Wizard.CloseDialog?
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.
Honestly... I don't know :( It is just legacy code, shall we change it? (I need to learn more about "UI" and "Wizard", I guess)
# | ||
# @return [Boolean] true if given source id is valid; false otherwise | ||
def valid_source?(source_id) | ||
source_id != -1 && source_id != nil # rubocop:disable Style/NonNilCheck |
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 about ![nil, -1].include?(source_id)
? Then you do not need rubocop disable.
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.
or better use constant like
INVALID_SOURCE_IDS = [nil, -1]
....
!INVALID_SOURCE_IDS.include?(source_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.
In fact, I was using your first suggestion but then I changed it for two main reasons:
- It was not clear to me the use of nil value, as I said in Refactor add on auto client #54 (comment) (@lslezak already explained the reason why it must still there).
- Despite to be less "ruby style", it seems to me more "simple" and readable the condition as it was.
# | ||
# @return [Boolean] true if given source id is valid; false otherwise | ||
def valid_source?(source_id) | ||
source_id != -1 && source_id != nil # rubocop:disable Style/NonNilCheck |
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 am keeping the original condition here, but to be honest I don't enterily understand why to concern about nil
if PkgFunctions::SourceCreateEx
seems to always return an integer value.
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.
Yes, it should return -1
in case of error. But in theory it might return nil
if an unhandled exception in the code is raised.
Pkg::
functions usually use nil
as an error value, I guess for some historical reasons it uses -1
here... I'd keep the nil
check unless it really hurts
# | ||
# @return [String] expanded url | ||
def expand_url_for(add_on, media_url) | ||
AddOnProduct.SetRepoUrlAlias( |
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.
Better in a single line, isn't it?
|
||
log.info("Preferred name: #{repo["name"]}") | ||
|
||
repos[repo_idx] = 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.
as ruby use reference and not copy, does it make sense this line?
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.
and if not, then all those index fun won't be needed and code can be much simplier.
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.
Some suggestions
Yast.import "PackageLock" | ||
Yast.import "Installation" | ||
Yast.import "String" | ||
# rubocop:disable Naming/FileName |
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.
Um, I cannot see any .rubocop.yml
file in the project. Without it tweaking the Rubocop config is probably useless...
And I'd prefer disabling it in the Rubocop config file instead of polluting the source code. See an example here.
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're right. I took borrowed the .rubocop.yml
from yast-storage-ng
to lint the code in my local copy... and then I forgot to remove those comments 😇
And I'd prefer disabling it in the Rubocop config file instead of polluting the source code.
Me too :) 👍
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.
Well, you can add it to the package. The long term goal is to use Rubocop for all code. We just did not have time to adapt all packages.
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.
Ok, I'll do it in its own PR :)
# reread agents, redraw wizard steps, etc. | ||
AddOnProduct.ReIntegrateFromScratch | ||
|
||
true |
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 if always returning true
is a good idea. What about adding some error handling? I guess that create_source(add_on)
above might fail...
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 I see, create_source
reports error internally using the report_error_for
method... But I'm still not sure if always returning true
is OK. If it is then it should be at least documented here that it's OK and the error is reported elsewhere.
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.
Ok, I'll think a little about it and make some changes to improve this.
Thanks
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.
@lslezak what about the new approach? (I just updated the PR)
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.
OK, looks better, the report_error_for
is more visible now.
@@ -3,20 +3,237 @@ | |||
require_relative "../../test_helper" | |||
require "add-on/clients/add-on_auto" | |||
|
|||
require "byebug" |
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.
Please remove this debugging require
, during RPM build the byebug
gem is not available.
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.
Ouch! 🤦♂️ 😅
I'll remove it in next update.
And Travis complains about a missing textdomain: https://travis-ci.org/yast/yast-add-on/builds/394877036#L381 |
# | ||
# @return [String] preferred name for add-on/repo | ||
def preferred_name_for(add_on, repo) | ||
return add_on["name"] if add_on.key?("name") # name in control file, bnc#433981 |
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 hope that add["name"] is enough, as for me nil value when this methods wants to return String.
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 do you mean?
It should be checked that value is not empty or nil before return it?
# @param [Hash] product | ||
# @param [Array] repo | ||
# @param [String] media | ||
# @param [String] pth |
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 looks wrong. I see two params.
# Returns preferred name for add-on/repo | ||
# | ||
# @param [Hash] product | ||
# @param [Array] 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.
more details will be useful here.
@@ -3,20 +3,237 @@ | |||
require_relative "../../test_helper" | |||
require "add-on/clients/add-on_auto" | |||
|
|||
require "byebug" |
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.
ugh, this should not be in final code as we really do not want to build depend on byebug,
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 forgot to remove it 😅 My fault. Thanks for catching it :)
before do | ||
allow(Yast::WFM).to receive(:Args).with(no_args).and_return([func]) | ||
allow(Yast::WFM).to receive(:Args).with(0).and_return(func) | ||
end | ||
|
||
context "when 'func' is 'Import'" do |
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 I usually did is that I believe AutoClient works and simply test directly import method, but it is up to you.
end | ||
end | ||
|
||
# FIXME: delete it? probably already tested in AutoClient |
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.
yes, whole dispathing is tested in auto client. In general I (not team rule) have rule for unit tests that I assume that other units works and I test only my unit.
https://github.com/yast/yast-yast2/blob/0d1f6001e99734c8da163d78c04bf53b029ba8c4/library/general/test/auto_client_test.rb
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.
Yes, you should only test the code implemented in your module. Testing the rest is out of scope and makes it fragile if the external code changes.
b1bdb10
to
0e0e739
Compare
1a51fb1
to
127d7fd
Compare
c428e46
to
c5ef642
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.
Some minor suggestions and fixes
if (srcid == -1 || srcid == nil) | ||
# revert back to the unexpanded URL to have the original URL | ||
# in the saved /etc/zypp/repos.d file | ||
Pkg.SourceChangeUrl(srcid, media) |
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.
Yes, that was wrong.
def summary | ||
formatted_add_on = AddOnProduct.add_on_products.map do |add_on| | ||
"<li>" \ | ||
"Media: #{add_on["media_url"]}, " \ |
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.
Use translated texts in the user visible summary and do not forget to HTML-escape the injected values, e.g.
# TRANSLATORS: %s is an add-on URL
_("URL: %s") % CGI.escapeHTML(add_on["media_url"]) +
# TRANSLATORS: %s is ...
_("Path: %s") % ... +
(BTW I'd use "URL" instead of "Media", that looks good only for dvd:///
URL, "URL" is more generic.)
Hint: For larger rich text blocks (this one is not that big IMO) you might even use ERB templates, see this example. Then you can use the usual h()
escaping just like in RoR...
formatted_add_on = AddOnProduct.add_on_products.map do |add_on| | ||
"<li>" \ | ||
"Media: #{add_on["media_url"]}, " \ | ||
"Path: #{add_on["product_dir"]}, " \ |
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.
Maybe we could skip the path attribute if it is not defined or is empty or /
. (As /
is the default value.)
And the same with the product name, we should skip it if it is not defined.
|
||
log.info("New source ID: #{source_id}") | ||
|
||
if [nil, -1].include?(source_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.
A valid source id is a positive number, so maybe simpler unless id > 0
would be better here. (JFYI: src id 0 refers to the packages installed in the system, it's not a real source.)
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.
If I understood you well previously, it is also needed to take into account the nil
value returned as error by Pkg::
functions due to possible unhandled exceptions, isn't it?
(and nil > 0
will raise a NoMethodError
exception)
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.
OK, makes sense.
|
||
return :report_error unless retry_on_error | ||
elsif !accepted_license?(add_on, source_id) | ||
# Lic |
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.
Incomplete 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.
Oops! 😇
def preferred_name_for(add_on, repo) | ||
add_on_name = add_on.fetch("name", nil) | ||
|
||
return add_on_name unless add_on_name.nil? || add_on_name.empty? # name in control file, bnc#433981 |
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.
NP: I prefer the comments above the code, trailing comments are a bit harder to read...
"Missing mandatory <media_url> value at index %d in the <add_on_products> definition.", | ||
"Skip the invalid product definition and continue with the installation?" | ||
] | ||
popup_prompt = format(_(error_message.join("\n")), index) |
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.
Unfortunately this won't work, the translation won't be found by gettext. You have to use it on the string literal directly. But you can still split it to more line easily:
error_message = _(
"Error in the AutoYaST <add_on> section.\n" \
"Missing mandatory <media_url> value at index %d in the <add_on_products> definition\n" \
"Skip the invalid product definition and continue with the installation?"
)
end | ||
end | ||
|
||
context "when there are missed medie_url values in given 'add_on_products'" do |
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.
Typo, should be media_url
here.
end | ||
|
||
describe "#read" do | ||
context "when cannot lock package" do |
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 module name is a bit confusing, but it's not a package lock but a package manager lock (so only one application can use it at one time).
end | ||
end | ||
|
||
context "when can lock package" do |
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 same here.
Guys, the PR was updated again, fixed and improved following suggestions from the code review. I did a few extra commits splitting each group of changes made. But maybe it will be better to squash them (or those least relevant) in a "Updates from code review" or similar single commit, what do you think? |
You can use the "Squash and Merge" GitHub option below, it squashes everything to one commit before merging. |
Making use of the base class Yast::Installation::Autoclient
Testing methods directly instead of do it through #run.
Use translations, escape HTML and omit useless "path" and "product" properties (empty or default values).
60aad9d
to
e8baa4b
Compare
7fe3c73
to
e3a196b
Compare
This PR is a refactorization of auto add-on client, following the approach suggested by @imobachgs and @jreidinger in #52 and discarding the first idea about refactoring only the #write method.
Help is needed to finish it, especially with the test which probably needs improve a lot. Also, help with naming and documentation is welcome.
I will do a self-review to write down some doubts in place.