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

Refactor add on auto client #54

Merged
merged 12 commits into from
Jul 23, 2018

Conversation

dgdavid
Copy link
Member

@dgdavid dgdavid commented Jun 21, 2018

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.

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)
Copy link
Member Author

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?

Copy link
Member

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
Copy link
Member

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

Copy link
Member Author

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(
Copy link
Member Author

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")
Copy link
Member

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 = []

{}
Copy link
Member

Choose a reason for hiding this comment

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

false
)

UI.CloseDialog
Copy link
Member

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?

Copy link
Member Author

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
Copy link
Member

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.

Copy link
Member

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)

Copy link
Member Author

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
Copy link
Member Author

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.

Copy link
Member

@lslezak lslezak Jun 21, 2018

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(
Copy link
Member Author

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
Copy link
Member

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?

Copy link
Member

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.

Copy link
Member

@lslezak lslezak left a 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
Copy link
Member

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.

Copy link
Member Author

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 :) 👍

Copy link
Member

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.

Copy link
Member Author

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
Copy link
Member

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...

Copy link
Member

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.

Copy link
Member Author

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

Copy link
Member Author

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)

Copy link
Member

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"
Copy link
Member

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.

Copy link
Member Author

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.

@lslezak
Copy link
Member

lslezak commented Jun 21, 2018

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
Copy link
Member

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.

Copy link
Member Author

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
Copy link
Member

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
Copy link
Member

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"
Copy link
Member

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,

Copy link
Member Author

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
Copy link
Member

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
Copy link
Member

@jreidinger jreidinger Jun 21, 2018

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

Copy link
Member

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.

@dgdavid dgdavid force-pushed the feature/refactor-add-on-auto-client branch from b1bdb10 to 0e0e739 Compare June 21, 2018 15:47
@coveralls
Copy link

coveralls commented Jun 21, 2018

Coverage Status

Coverage increased (+2.3%) to 18.317% when pulling e3a196b on dgdavid:feature/refactor-add-on-auto-client into 3159a10 on yast:master.

@dgdavid dgdavid force-pushed the feature/refactor-add-on-auto-client branch 2 times, most recently from 1a51fb1 to 127d7fd Compare June 21, 2018 18:19
@dgdavid dgdavid changed the title [WIP] Refactor add on auto client Refactor add on auto client Jun 28, 2018
@dgdavid dgdavid force-pushed the feature/refactor-add-on-auto-client branch from c428e46 to c5ef642 Compare June 28, 2018 07:30
Copy link
Member

@lslezak lslezak left a 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)
Copy link
Member

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"]}, " \
Copy link
Member

@lslezak lslezak Jun 28, 2018

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"]}, " \
Copy link
Member

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)
Copy link
Member

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.)

Copy link
Member Author

@dgdavid dgdavid Jun 28, 2018

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)

Copy link
Member

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
Copy link
Member

Choose a reason for hiding this comment

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

Incomplete comment?

Copy link
Member Author

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
Copy link
Member

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)
Copy link
Member

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
Copy link
Member

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
Copy link
Member

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
Copy link
Member

Choose a reason for hiding this comment

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

The same here.

@dgdavid
Copy link
Member Author

dgdavid commented Jun 28, 2018

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?

@lslezak
Copy link
Member

lslezak commented Jul 23, 2018

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
@dgdavid dgdavid force-pushed the feature/refactor-add-on-auto-client branch from 60aad9d to e8baa4b Compare July 23, 2018 08:28
@dgdavid dgdavid force-pushed the feature/refactor-add-on-auto-client branch from 7fe3c73 to e3a196b Compare July 23, 2018 08:47
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.

None yet

4 participants