From 776bca07cd4b3996a39035e90232c99599ed2663 Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Thu, 16 Oct 2014 11:34:19 -0500 Subject: [PATCH] Add Atlassian Bamboo service --- CHANGELOG | 1 + .../projects/services_controller.rb | 3 +- app/models/project.rb | 3 +- app/models/project_services/bamboo_service.rb | 105 ++++++++++++++++++ app/views/projects/services/_form.html.haml | 4 +- doc/README.md | 1 + doc/project_services/bamboo.md | 60 ++++++++++ doc/project_services/project_services.md | 18 +++ features/project/service.feature | 6 + features/steps/project/services.rb | 20 ++++ 10 files changed, 218 insertions(+), 3 deletions(-) create mode 100644 app/models/project_services/bamboo_service.rb create mode 100644 doc/project_services/bamboo.md create mode 100644 doc/project_services/project_services.md diff --git a/CHANGELOG b/CHANGELOG index 01ae3562ded..f01267c460c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ v 7.5.0 - Add time zone configuration on gitlab.yml (Sullivan Senechal) - Fix LDAP authentication for Git HTTP access - Fix LDAP config lookup for provider 'ldap' + - Add Atlassian Bamboo CI service (Drew Blessing) v 7.4.2 - Fix internal snippet exposing for unauthenticated users diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index b50f6286459..a5f30dcfd9d 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -41,7 +41,8 @@ class Projects::ServicesController < Projects::ApplicationController params.require(:service).permit( :title, :token, :type, :active, :api_key, :subdomain, :room, :recipients, :project_url, :webhook, - :user_key, :device, :priority, :sound + :user_key, :device, :priority, :sound, :bamboo_url, :username, :password, + :build_key ) end end diff --git a/app/models/project.rb b/app/models/project.rb index 613f98ba44b..c58c9b551c9 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -65,6 +65,7 @@ class Project < ActiveRecord::Base has_one :gemnasium_service, dependent: :destroy has_one :slack_service, dependent: :destroy has_one :buildbox_service, dependent: :destroy + has_one :bamboo_service, dependent: :destroy has_one :pushover_service, dependent: :destroy has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" has_one :forked_from_project, through: :forked_project_link @@ -313,7 +314,7 @@ class Project < ActiveRecord::Base end def available_services_names - %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack pushover buildbox) + %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack pushover buildbox bamboo) end def gitlab_ci? diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb new file mode 100644 index 00000000000..b9eec9ab21e --- /dev/null +++ b/app/models/project_services/bamboo_service.rb @@ -0,0 +1,105 @@ +class BambooService < CiService + include HTTParty + + prop_accessor :bamboo_url, :build_key, :username, :password + + validates :bamboo_url, presence: true, + format: { with: URI::regexp }, if: :activated? + validates :build_key, presence: true, if: :activated? + validates :username, presence: true, + if: ->(service) { service.password? }, if: :activated? + validates :password, presence: true, + if: ->(service) { service.username? }, if: :activated? + + attr_accessor :response + + after_save :compose_service_hook, if: :activated? + + def compose_service_hook + hook = service_hook || build_service_hook + hook.save + end + + def title + 'Atlassian Bamboo CI' + end + + def description + 'A continuous integration and build server' + end + + def help + 'You must set up automatic revision labeling and a repository trigger in Bamboo.' + end + + def to_param + 'bamboo' + end + + def fields + [ + { type: 'text', name: 'bamboo_url', + placeholder: 'Bamboo root URL like https://bamboo.example.com' }, + { type: 'text', name: 'build_key', + placeholder: 'Bamboo build plan key like KEY' }, + { type: 'text', name: 'username', + placeholder: 'A user with API access, if applicable' }, + { type: 'password', name: 'password' }, + ] + end + + def build_info(sha) + url = URI.parse("#{bamboo_url}/rest/api/latest/result?label=#{sha}") + + if username.blank? && password.blank? + @response = HTTParty.get(parsed_url.to_s, verify: false) + else + get_url = "#{url}&os_authType=basic" + auth = { + username: username, + password: password, + } + @response = HTTParty.get(get_url, verify: false, basic_auth: auth) + end + end + + def build_page(sha) + build_info(sha) if @response.nil? || !@response.code + + if @response.code != 200 || @response['results']['results']['size'] == '0' + # If actual build link can't be determined, send user to build summary page. + "#{bamboo_url}/browse/#{build_key}" + else + # If actual build link is available, go to build result page. + result_key = @response['results']['results']['result']['planResultKey']['key'] + "#{bamboo_url}/browse/#{result_key}" + end + end + + def commit_status(sha) + build_info(sha) if @response.nil? || !@response.code + return :error unless @response.code == 200 || @response.code == 404 + + status = if @response.code == 404 || @response['results']['results']['size'] == '0' + 'Pending' + else + @response['results']['results']['result']['buildState'] + end + + if status.include?('Success') + 'success' + elsif status.include?('Failed') + 'failed' + elsif status.include?('Pending') + 'pending' + else + :error + end + end + + def execute(_data) + # Bamboo requires a GET and does not take any data. + self.class.get("#{bamboo_url}/updateAndBuild.action?buildKey=#{build_key}", + verify: false) + end +end diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index 16d59d1fe9d..1151f22c7e8 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -28,7 +28,7 @@ - @service.fields.each do |field| - name = field[:name] - - value = @service.send(name) + - value = @service.send(name) unless field[:type] == 'password' - type = field[:type] - placeholder = field[:placeholder] - choices = field[:choices] @@ -45,6 +45,8 @@ = f.check_box name - elsif type == 'select' = f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" } + - elsif type == 'password' + = f.password_field name, class: 'form-control' .form-actions = f.submit 'Save', class: 'btn btn-save' diff --git a/doc/README.md b/doc/README.md index a8e21f75714..7343d5ae273 100644 --- a/doc/README.md +++ b/doc/README.md @@ -5,6 +5,7 @@ - [API](api/README.md) Explore how you can access GitLab via a simple and powerful API. - [Markdown](markdown/markdown.md) Learn what you can do with GitLab's advanced formatting system. - [Permissions](permissions/permissions.md) Learn what each role in a project (guest/reporter/developer/master/owner) can do. +- [Project Services](project_services/project_services.md) Explore how project services can integrate a project with external services, such as for CI. - [Public access](public_access/public_access.md) Learn how you can allow public and internal access to a project. - [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects. - [Web hooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project. diff --git a/doc/project_services/bamboo.md b/doc/project_services/bamboo.md new file mode 100644 index 00000000000..51668128c62 --- /dev/null +++ b/doc/project_services/bamboo.md @@ -0,0 +1,60 @@ +# Atlassian Bamboo CI Service + +GitLab provides integration with Atlassian Bamboo for continuous integration. +When configured, pushes to a project will trigger a build in Bamboo automatically. +Merge requests will also display CI status showing whether the build is pending, +failed, or completed successfully. It also provides a link to the Bamboo build +page for more information. + +Bamboo doesn't quite provide the same features as a traditional build system when +it comes to accepting webhooks and commit data. There are a few things that +need to be configured in a Bamboo build plan before GitLab can integrate. + +## Setup + +### Complete these steps in Bamboo: + +1. Navigate to a Bamboo build plan and choose 'Configure plan' from the 'Actions' +dropdown. +1. Select the 'Triggers' tab. +1. Click 'Add trigger'. +1. Enter a description such as 'GitLab trigger' +1. Choose 'Repository triggers the build when changes are committed' +1. Check one or more repositories checkboxes +1. Enter the GitLab IP address in the 'Trigger IP addresses' box. This is a +whitelist of IP addresses that are allowed to trigger Bamboo builds. +1. Save the trigger. +1. In the left pane, select a build stage. If you have multiple build stages +you want to select the last stage that contains the git checkout task. +1. Select the 'Miscellaneous' tab. +1. Under 'Pattern Match Labelling' put '${bamboo.repository.revision.number}' +in the 'Labels' box. +1. Save + +Bamboo is now ready to accept triggers from GitLab. Next, set up the Bamboo +service in GitLab + +### Complete these steps in GitLab: + +1. Navigate to the project you want to configure to trigger builds. +1. Select 'Settings' in the top navigation. +1. Select 'Services' in the left navigation. +1. Click 'Atlassian Bamboo CI' +1. Select the 'Active' checkbox. +1. Enter the base URL of your Bamboo server. 'https://bamboo.example.com' +1. Enter the build key from your Bamboo build plan. Build keys are a short, +all capital letter, identifier that is unique. It will be something like PR-BLD +1. If necessary, enter username and password for a Bamboo user that has +access to trigger the build plan. Leave these fields blank if you do not require +authentication. +1. Save or optionally click 'Test Settings'. Please note that 'Test Settings' +will actually trigger a build in Bamboo. + +## Troubleshooting + +If builds are not triggered, these are a couple of things to keep in mind. + +1. Ensure you entered the right GitLab IP address in Bamboo under 'Trigger +IP addresses'. +1. Remember that GitLab only triggers builds on push events. A commit via the +web interface will not trigger CI currently. diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md new file mode 100644 index 00000000000..20a69a211dd --- /dev/null +++ b/doc/project_services/project_services.md @@ -0,0 +1,18 @@ +# Project Services + +__Project integrations with external services for continuous integration and more.__ + +## Services + +- Assemblia +- [Atlassian Bamboo CI](bamboo.md) An Atlassian product for continous integration. +- Build box +- Campfire +- Emails on push +- Flowdock +- Gemnasium +- GitLab CI +- Hipchat +- PivotalTracker +- Pushover +- Slack diff --git a/features/project/service.feature b/features/project/service.feature index af88eaefa8f..88fd038d45f 100644 --- a/features/project/service.feature +++ b/features/project/service.feature @@ -54,3 +54,9 @@ Feature: Project Services And I click email on push service link And I fill email on push settings Then I should see email on push service settings saved + + Scenario: Activate Atlassian Bamboo CI service + When I visit project "Shop" services page + And I click Atlassian Bamboo CI service link + And I fill Atlassian Bamboo CI settings + Then I should see Atlassian Bamboo CI service settings saved diff --git a/features/steps/project/services.rb b/features/steps/project/services.rb index 5bd60f99c84..17d62210d10 100644 --- a/features/steps/project/services.rb +++ b/features/steps/project/services.rb @@ -14,6 +14,7 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps page.should have_content 'GitLab CI' page.should have_content 'Assembla' page.should have_content 'Pushover' + page.should have_content 'Atlassian Bamboo' end step 'I click gitlab-ci service link' do @@ -137,4 +138,23 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps find_field('Priority').find('option[selected]').value.should == '1' find_field('Sound').find('option[selected]').value.should == 'bike' end + + step 'I click Atlassian Bamboo CI service link' do + click_link 'Atlassian Bamboo CI' + end + + step 'I fill Atlassian Bamboo CI settings' do + check 'Active' + fill_in 'Bamboo url', with: 'http://bamboo.example.com' + fill_in 'Build key', with: 'KEY' + fill_in 'Username', with: 'user' + fill_in 'Password', with: 'verySecret' + click_button 'Save' + end + + step 'I should see Atlassian Bamboo CI service settings saved' do + find_field('Bamboo url').value.should == 'http://bamboo.example.com' + find_field('Build key').value.should == 'KEY' + find_field('Username').value.should == 'user' + end end