Semaphore Blog

News and updates from your friendly continuous integration and deployment service.

MySQL Strict Mode And You

We’ve recently upgraded MySQL 5.5 to 5.6 in our platform. Along with many performance and stability improvements, the new version also has strict mode turned on by default, which means it has stricter syntax and data validation checking. This, of course, is a good thing from your data’s standpoint but it may also cause some unexpected errors in your builds.

To turn off MySQL’s strict mode, you’ll have to add the following command to your build commands in project settings.

mysql -u root -psemaphoredb -e "SET @@global.sql_mode= '';"

For more information about MySQL modes, you can check out the official documentation here.

Trigger a Deploy Over API And More Updates

As our API evolves, a need for an action that allows user to trigger a deploy via API appeared.

This feature is now available. From now on you will be able to trigger deploys through our API, easy as:

curl -d "auth_token=XXX" -v https://semaphoreapp.com/api/v1/projects/:project_hash/:branch_id/builds/:build_number/deploy/:server_id

The API documentation has been updated accordingly with these latest additions.

Also, we would like to announce that there are a few additions to our server API response structures. You can find the latest specifications in the documentation.

Upcoming Platform Update on May 5th

The upcoming platform update is scheduled for Monday, May 5, 2014.

Bundler is updated to version 1.6.2 featuring a lot of goodies, including 10x faster Gemfile resolving.

Firefox goes up to version 29, requiring bundle update selenium-webdriver for most projects that use that gem.

ElasticSearch has been also updated and it’s now on version 1.1.1.

MySQL is upgraded to version 5.6 with lots of performance and stability improvements. To avoid an error which pops up when the cached mysql gem tries to use the new library, we will remove the caches for all projects which use this gem. If a few projects slip through our fingers, please contact us.

rake aborted!
Incorrect MySQL client library version! This gem was compiled for 5.5.35 but
the client library is 5.6.17.

A quick remedy for this would be to include rm -rf .bundle or rm -rf vendor/bundle to your build commands in project settings.

A full list of changes is available in the platform changelog.

Update 2014-05-07: Firefox 29 was added to the release.

Heartbleed

As you have probably heard, a severe security bug in OpenSSL dubbed Heartbleed was uncovered on April 7th. It allows anyone to read 64k chunks of memory of the systems using the vulnerable versions of OpenSSL, leaving no trace in common system or server logs.

All Semaphore’s current infrastructure is using OpenSSL and was thus affected and needed to be updated. Here’s what we did and what we recommend you to do as well.

OpenSSL upgrade

We upgraded OpenSSL to a secure version on our front-end system on April 8th 9:47 AM UTC. Immediate next step was to replace SSL certificates. Once that was in place, the platform was secure from any future attacks. We then proceeded to upgrade OpenSSL and certificates on our build platform as well.

Passwords, API tokens and sessions

We have found no evidence of harm, but absence of evidence does not equal evidence of absence, hence we recommend that you change your Semaphore password and reset your API token. We have implemented a one-click way for resetting the API token for this purpose, you can find it in project settings > API. We have also reset all user sessions.

GitHub tokens

GitHub issued their response to Heartbleed. We encourage you to use their 2FA system if you are not already. They implemented an API endpoint for resetting OAuth tokens, which we applied to all Semaphore users.

Heroku tokens

If you are deploying from Semaphore to Heroku, and you changed your Heroku password (which you should do), then the API token that Semaphore is using internally to run db:migrate for you is no longer valid. We have implemented an easy way for you to set a new value of Heroku API token, which you can find on your server settings page.

Contacting us

If you still have any concerns, please do get in touch, we are happy to help and answer any questions. You can reach us via the “Support” link inside the app or via semaphore@renderedtext.com.

A New Way To Read Build Results

We are happy to announce a new state of the art reporting feature!

As we are always in pursuit of greatness and bleeding edge technology, this time we have taken inspiration from the past in order to do something completely new. From now on, for each and every build Semaphore will send you a full test report, printed in crisp dot-matrix font directly to your address. We expect first deliveries to arrive today after 2PM UTC.

This feature is available to all Pro customers. To enable it, simply fill in your mailing address in your account settings.

Your paper reports will be wrapped in a water resistant package envelope, so they will will be saved from all weather hazards.

All modesty aside, we believe that this could be a start of a new era in the CI world and the way we communicate with our customers.

Managing Externals in Ruby Tests

In this post we’ll explore options for dealing with external resources when writing tests. Generally, a common solution is to use a mock instance of the resource that is not part of your system under test. It is however important to make sure that your mock, or stubbed response is a faithful copy and does not get out of date.

Bending time

With Timecop, it is not necessary to create records and then modify their timestamps manually in order to verify some time-based conditions. Consider the following example:

describe ".recent" do

  before do
    2.times do
      post = create(:post)
      post.update_attribute(:created_at, 2.months.ago)
    end

    @recent_post = create(:post)
    @recent_post.update_attribute(:created_at, 10.days.ago)
  end

  it "returns posts from the past month" do
    Post.recent.count.should eql(1)
    Post.recent.should include(@recent_post)
  end
end

Real-life examples of course get more messy, for example when you’re dealing with more elaborate conditions for a leaderboard. Compare the same spec with a version using Timecop:

describe ".recent" do

  before do
    Timecop.travel(2.months.ago) do
      2.times { create(:post)
    end

    Timecop.travel(10.days.ago) { @recent_post = create(:post) }
  end

  it "returns posts from the past month" do
    Post.recent.count.should eql(1)
    Post.recent.should include(@recent_post)
  end
end

Making HTTP requests

Depending on external resources makes the test suite slow and prone to unexpected errors in case of connectivity issues or service outages. For these reasons you should avoid making real HTTP requests in your tests. A common solution is to stub the requests and, optionally, responses. Ruby has very good tools to achieve this.

Webmock lets you stub and set expectations on HTTP requests:

stub_request(:get, "www.example.com").with(:query => {"a" => ["b", "c"]})

RestClient.get("http://www.example.com/?a[]=b&a[]=c")    # ===> Success

When dealing with many HTTP requests, especially if they are important enough that you want to stub the full response, I recommend using VCR. It works with any test framework and lets you record your test suite’s HTTP interactions in YAML files and “replay” them, ie reuse them as stubbed responses, during future test runs. We are using VCR to test Semaphore’s interaction with the GitHub API, for example.

describe HookCreationService do

  let(:project) { FactoryGirl.build(:project, :hash_id => "1a3b5") }

  vcr_options = { :cassette_name => "HookCreationService/connection_working",
                  :record => :new_episodes }

  context "connection working", vcr: vcr_options do

    it "sets project's github_hook_id" do
      project.should_receive(:update_attribute)
        .with(:github_hook_id, instance_of(Fixnum))

      HookCreationService.execute(project)
    end
  end
end

The first time this test runs (in practice on your development machine), the actual HTTP request is made. VCR stores the full response, including headers in fixtures/cassette_library/HookCreationService/connection_working.yml. Future runs of the test will use Webmock under the hood to stub the request and return the saved response. Not only will they be fast, as they won’t reach for the internet, but you can be sure that they’ll be accurate, since they will use a bit-exact copy of response. If we ever hit that URL with different options, VCR will record a new copy. All this is provided by the :new_episodes option. Configuration can be provided globally of course so you don’t repeat yourself.

You can find more information about VCR on its documentation site.

A word of caution: VCR does not insulate you from changes in external APIs. If an API changes and you are not paying attention, your tests will still be passing but the production system will stop working. Ideally your API provider is responsible and is not making any changes without announcing them. In that case, follow the API changes feed and when something does change, delete your cassette files and re-record them.

Testing an OAuth flow

Developers of applications that use OAuth to authenticate users via a third-party service can find it challenging to test that flow. I will present how we test GitHub authentication for Semaphore.

If you are using the excellent OmniAuth gem and one of its many providers, you have an option to use its facilities for integration testing. In short, you can short-circuit the flow to immediately redirect to the authentication callback (that’s a route in your app) with a provided mock hash. This is good because a fairly simple hash is what OmniAuth distills for you in production as well.

Since we do integration testing with Cucumber, this is our features/support/omniauth.rb:

Before("@omniauth_test") do
  OmniAuth.config.test_mode = true

  OmniAuth.config.mock_auth[:github] = {
    "uid" => "1",
    "provider" => "github",
    "info" => { "nickname" => "darkofabijan", "name" => "Darko Fabijan" },
    "credentials" => { "token" => "63146da137f3612f..." }
  }
end

After("@omniauth_test") do
  OmniAuth.config.test_mode = false
end

The first time this was set up, we authenticated Semaphore (a local development instance or production, does not matter) with GitHub and pasted the credentials token above. The Cucumber suite is using VCR, so the next step was to record cassettes with real API responses. A scenario only needs to include the @omniauth_test tag to apply this token to all requests to GitHub API:

Feature: Building projects

  @omniauth_test @javascript
  Scenario: New user signs up, creates a project without collaborators and builds it
    Given I am on the homepage
    #...

Again, first test runs create YAML files with real responses which we can reuse in developing the feature:

---
http_interactions:
- request:
    method: get
    uri: https://api.github.com/user/repos?access_token=63146da137f3612f...
    body:
      encoding: US-ASCII
      string: ""
    headers:
      Accept-Encoding:
      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
      Accept:
      - "*/*"
      User-Agent:
      - Ruby
  response:
    status:
      code: 200
      message: OK
    headers:
      Server:
      - GitHub.com
      #...

At this point the test suit can run autonomously. The only thing left, as a security measure, is to revoke access on GitHub in order to invalidate this particular API token.

New Build and Deploy Emails

We are very happy to announce that Semaphore is now sending new and more helpful build and deploy emails.

So far, we have been sending out plain text messages to report your build or deploy results, but now you can enjoy our new HTML layout that closely resembles the pages you are used to seeing on Semaphore. Here’s what it looks like:

In case when a command fails, the email will include a tail of its log.

Different people have very different needs and workflow. You can integrate Semaphore with Slack and Campfire, you can even use webhooks, but from now on even emails alone could give you a nice and pleasurable experience.

If you prefer plain text email, it is still available since the new emails are sent as multipart.

Slack Integration

We’re very happy to announce official integration between Semaphore and Slack.

Slack is a new team communication service with apps for all major platforms. We’ve recently started using it ourselves and it’s been a great experience.

The integration lets you receive status messages from Semaphore when a build or deploy finishes right in your Slack room of choice. To set it up, simply go to https://my.slack.com/services/new/semaphore and follow the instructions. You’ll be up and running in a minute.

Big thanks to the Slack team for working with us on this feature.

Upcoming Platform Update on March 5

The upcoming platform update is scheduled for Wednesday, March 5 2014.

Ruby 2.1.1 is added to the stack. Rubies 2.0.0 and 1.9.3 get upgraded patchlevels, so bundle update debugger will likely be necessary.

Firefox goes up to version 27, requiring bundle update selenium-webdriver for most projects that use that gem.

Node and NPM are updated to the latest versions too.

A full list of changes is available in the platform changelog.

Update March 6: ElasticSearch package changed and it no longer runs the server on boot. Users will need to add sudo service elasticsearch start as their first build setup command. Sorry about that, we’ll have it fixed shortly.

Update March 17: ElasticSearch server now runs on boot again.

Get future posts like this one in your inbox.

Follow us on