Thank you for your code submission and I hope you find this review useful.
#!/usr/bin/env ruby
require 'bundler/setup'
require 'octokit'
Let's improve argument handling so we can catch if no message or issue is passed. It's possible that we could have a repo and nothing else, but the argument handling does not deal with the case for when one argument is passed (the repo). It doesn't make much sense to create an empty issue with no message.
Instead of
you could use :if ARGV.empty?
if ARGV.empty? or ARGV.length < 2
if ARGV.empty?
puts "Post new issues or, if given an issue id, add a comment."
puts "Usage: gh-simple-issue REPO [ISSUEID] <text>"
exit 1
end
Consider adding a
begin,rescueblock for error handling statement here so that you can catch if authentication fails, such as the token not being set or login not being valid.
token = ENV['HUBOT_GITHUB_TOKEN']
client = Octokit::Client.new(
:login => "hubot",
:access_token => token
)
repo = issue = nil
Now lets improve how we can handle deciding if the second argument is an ISSUEID or part of the message that goes into our issue. For this, we'll need to test if the second argument is a number or simply a string text of the message. It might be better if we handle that with an early assignment such as:
repo, *words = ARGV
This also takes care of the missing message from the third argument and beyond. Also, although
repois now a string,wordsis now anArraythat contains the remaining message and potentially the ISSUEID. Lets convertwordsfrom anArrayto aStringso we can continue processing it as aString.
words = words.join(' ')
Now that we have the
repovalue assigned, it's a fairly safe assumption that we will have at least the remaining message because of the earlier check for more than two arguments for the input. We now simply need to determine if the first word in thewordsvariable is aIntegeror not so that it can be assigned to theissuevariable.
The
issuevariable assignment should then happen in two steps.
- First determine if the first word in
wordsvariable can be converted to anIntegeror not, set it tonilif the conversion fails with therescuestatement. We'll use.partitionto get the first word from thewordsvariable. If theIntegerconversion fails thenrescuewill catch the error and assignnilas the value.issue = Integer(words.partition(' ').first) if Integer(words.partition(' ').first) rescue nil
- If issue was assigned a number and is not
nil, then remove the first word fromwordsstring and continue.words = words.split(' ')[1..-1].join(' ') unless issue.nil?
** Now you should be ready to remove this section if you choose to implement the new argument handling **
if ARGV.length >= 3
repo = ARGV[0]
issue = ARGV[1]
words = ARGV[2]
elsif ARGV.length >= 2
repo = ARGV[0]
words = ARGV[1]
end
Note: one last possibility in argument handling is that the ISSUEID was provided but no remaining message was given. In this case an empty comment will be appended to the issue, so it might be good to check for that if thats not a desired behavior.
nwo = "github/#{repo.downcase}"
The next two calls for client should have
rescueblocks to deal with error handling.
if issue
client.add_comment(nwo, issue, words)
else
A few considerations on the next line:
- Consider using the
socketlibrary here and the methodSocket.gethostnameinstead of a call out. This may prevent this code from being portable on platforms that don't include thehostnamecommand (like Windows).- Consider providing a default for
CAMPFIRE_USERif the environment variable is not set. This can be done as follows:#{(ENV["CAMPFIRE_USER"] || 'anonymous').strip}, otherwise the.stripcommand will fail on anilresults fromENV.- This doesn't seem to be an issue at the moment but if in the future you change the
hostname -scallout to include any variables, you might make this code susceptible to command injection. An early best practice might be to make the call out forhostname -sintosystem('hostname','-s'), so that any future edits might not accidentally lead to command injection. Another good reason to consider the first point.
client.create_issue(nwo, "Opened from #{`hostname -s`.strip} by #{ENV["CAMPFIRE_USER"].strip}", words)
end
Thanks! and I hope you enjoyed this review.
-- wenlock