PullReview: Badge and integration with BitBucket and GitLab

PullReview recently gets a few new features:

  • Badge
  • Public Review for Public Repo
  • BitBucket and GitLab
  • and lots more:
    • HipChat notification
    • Performance of the home page
    • Profile
    • Heartbleed
    • Support Contact

Badge

Badges in README.md are a very common way to inform people about your project good health. PullReview now provides its own badges:

badge PullReview KO

badge PullReview OK

Each badge presents a brief status as following:

  • ✗ the number of detected issues
  • ✔ the number of fixed issues
  • (+ the number of issues fixed since the previous review)

It will be colored depending on the progress:

  • red if
    • more issues have just been added than fixed
    • there are more to fix than fixed
  • otherwise it will be green

When you click on the badge you’ll then access the corresponding review page.

You’ll find the link and the markdown snippet for the badge just below the review title by clicking “Badge urls”.

badge-urls

The badges are also available for private repositories. In that case, the URI also contains a unique token given the access to the badge. The URI is then enough in itself to see the badge (but only the badge). Share it carefully.

 Share your badge and show off all your improvements!


Public Repositories reviews are now public

You can now share the URI of your review with anybody, and they will have access to your review. For instance, by clicking on a badge, a person can visit your review and discover its details. All the details are shared except the security vulnerabilities. To avoid premature disclosure, those ones are only readable by the owner of the review.


BitBucket and GitLab support

It’s now possible to review a repo hosted either on BitBucket or on GitLab. On the list of repositories, click on the button “Add a repository”

add-repo-button

Then fill the form to add your BitBucket or GitLab repo:

add-repo-form

Notice, that it’s also possible for GitHub repository when you didn’t grant us enough permission to retrieve the list of your repositories, and add deploy key and webhook.

For BitBucket as for GitHub, you can also grant us some permission that will ease your setup: retrieving the list of all your repositories and one-click setup adding deploy key and webhook.

bitbucket-auth


HipChat notification

HipChat is one of the great chat applications. It’s really a great way to communicate but also to be notified of everything that happens inside your team. In addition to Email and GitHub Status, you can now be notified directly into your HipChat room when a review is ready. Just go on your account page, browse the Notification tab, and setup the connection with HipChat

hipchat-form


Performance of the home page

We’ve improved the performance of the home page with the list of available reviews. For some of you, it will make a big difference as it’s no more slowed down by the size of your reviews.

We’re working now on the performance of the review page.


Profile

As you may have noticed, there is now a profile page

profile

Stay tuned – more and more metrics, awards and badges coming your way in the next weeks.


HeartBleed

You’ve certainly heard of HeartBleed vulnerability. We’ve already took several measures including:

  • We’ve upgraded all our systems to use the newer and protected version of OpenSSL. We did it on the productions servers the day just after the vulnerability became public.
  • We’ve reissued new SSL Certificates and revoked the old ones.

We’re still working on the issue, but on less urgent side effects.

For GitHub, BitBucket, and GitLab, we advise you to read their respective blog post on the topic. In addition, as PullReview relies on GitHub for login, we recommend you to follow their recommendations:


Support Contact

If you need support, have any questions, comments or feedback, there are several ways to contact us:


Happy Spring!

The sunny days are back for most of us. Always a great time to get out, spend time with friends and family, and leave the code behind you.

We’re here if you have any questions or need anything. As listed above, there are plenty of way to reach us.





7 daily use cases of Ruby String

Strings are everywhere. You deal with String instances not only every day, but probably every minute. They came from files, databases, REST APIs, or you simply use them to print results. It’s a pervasive representation, and Ruby provides plenty to ease its manipulation. But String comes with its own share of problems and you won’t always find a quick solution in the doc like how to deal with invalid byte sequence or convert back a String to a Date with an uncommon format.

Below, I share 7 common use cases of String I met very often and should be useful to you.

  1. How to remove enclosing characters like parenthesis?
  2. How to compare two Strings insensitively?
  3. How to clean a String by removing newline, carriage return, leading and trailing spaces?
  4. How to convert a String to a Regexp?
  5. How to convert a String to a Date with uncommon format?
  6. How to remove accents?
  7. How to clean up invalid byte sequences?

1. How to remove enclosing characters like parenthesis?

You retrieve data from a file:

line = "(this is a data from the file)"

The data is always wrapped by () that you don’t want. You can get the data without them as following:

line[1..-2]
# =>"this is a data from the file"

This actually removes the first and last characters of the String.

reference: String#[], String#slice

2. How to compare two Strings insensitively?

In an online shop, the user can search for product by their name:

products = [
 'Banana',
 'Apple',
 'Orange'
]

# ...

search_string = 'apple'

You don’t want to force your users to be case sensitive (they aren’t), so you can do:

products.select { |product| product.casecmp(search_string) == 0 }
# => ['Apple']

As pointed out by apeiros in the comments, it won’t work for any non-ASCII characters. So, a better version would be:

products.select { |product| product =~ /#{Regexp.escape(search_string)}/i }

reference: String#casecmp

3. How to clean a String by removing newline, carriage return, leading and trailing spaces?

In a little script, you read data from the console:

command = gets

You can clean up what you read by simply doing:

command = gets.strip

Thanks to apeiros for making me notice that strip removes also trailing newline and carriage return. It’s not needed to use chomp.

reference: String#chomp, String#strip

4. How to convert a String to a Regexp?

You’re developing a Gem that maintains a database of locations of files. In the configuration file, the user can blacklist specific pathnames with regular expressions. You retrieved one of them (you don’t want to locate the files in your trash):

blacklisted_pathname = '\.\/\.trash'

You can then use it to directly check:

file_paths.select  { |file_path| !(file_path =~ /#{blacklisted_pathname}/) }

or keep it for later:

r = Regexp.new blacklisted_pathnam

Don’t forget to correctly escaping in your string, or even better, use Regexp.escape as suggested by apeiros.

reference: Regexp#new, Regular Expressions literal and interpolation
Aside note: for that particular use case, you should probably use File#fnmatch

5. How to convert a String to a Date with uncommon format?

In an old database, the dates are stored as String as following:

date = '1979;4;2'

You can convert it as a Date as following:

Date.strptime(date, '%Y;%m;%d')
# => #<Date: 1979-04-02 ((2443966j,0s,0n),+0s,2299161j)>

reference: Date#strptime

6. How to remove accents?

You’re building a web app and you’d like to allow a quick search among the members like

'Kurt Gödel'

Accents and diacritics could be easily forgotten, and you want to remove them from the searched string. You can do it easily with ActiveSupport

require 'active_support/inflector' # not necessary if Rails

ActiveSupport::Inflector.transliterate('Kurt Gödel')
# => "Kurt Godel"

reference: Inflector#transliterate

7. How to clean up invalid byte sequences?

You read a text File encoded in UTF-8. You manipulate each of its line, but at some point you get the error

ArgumentError: invalid byte sequence in UTF-8

on the line

line = "This is an invalid byte sequence \244"
# => "This is an invalid byte sequence \xA4"

Well, you need to clean up your line before working on it by using scrub:

# if &lt; 2.1, use the backport gem string-scrub
# by adding to your Gemfile
# <code>gem 'string-scrub'
</code>
# if &gt;= 2.1, it's part of String (yeah \o/)

line.scrub!('')
# =&gt; "This is an invalid byte sequence "

Old way:

<del>line.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
# =&gt; "This is an invalid byte sequence "</del>

But if you have non-ASCII characters, it will remove them. In that case, you should go for a solution as apeiros’ one.

references: String#encode!, String#scrub! (2.1)
read also: Fight Back UTF-8 Invalid Byte Sequences

What’s your daily use cases of Strings?

Compared with daily use cases of Array, Hash, or Regexp, some for String are very basic, but very common. I love how Ruby allows you to deal with slicing for instance. It’s very elegant.

What’s yours? What are your typical daily use cases of String and elegant Ruby to resolve them?





When should I use a Set in Ruby?

You develop a small contact manager for a client.

Contact = Struct.new(:name, :email)

One important feature is the possibility to define a list of contacts.

granny = Contact.new('granny', 'granny@weatherwax.me')
bill = Contact.new('bill', 'bill@door.me')

At first, you started with an array,

contacts = []

but you realize quickly that you have to check for duplicates. You end in many places with something like:

contacts << granny unless contacts.include? granny

or

contacts.uniq!

Last time you were working with the list, you needed to send a campaign email to each contact:

contacts << granny
# => [granny]

contacts << granny
# => [granny, granny]

contacts << bill
# => [granny, granny, bill]

# …

contacts.each do |contact|
  contact.send_campaign # oups!
end

You forgot to check for duplicates, you shipped it, and the campaign was sent twice to granny!

You don’t like that, and you’re right. Indeed, the code is fragile: you shouldn’t watch for the uniqueness constraint, it should be built in.

If you need a collection with uniqueness guaranteed, use a Set:

require 'set'

#...

contacts = Set.new

# ...

contacts << granny
# => {granny}

contacts << granny
# => {granny}

contacts << bill
# => {granny, bill}

contacts.each do |contact|
  contact.send_campaign # yeah!
end

Of course, Array is a fine structure too – if duplicates are allowed or you need to access the nth element. In the end, you should work with classes properly representing your data: they will behave as you expect. In 99%, it’s more important than performance consideration, or you’ll end with fragile code.