From 77f8a1e392b64f51326df8aebdc77e97af07bfed Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 2 Nov 2015 17:27:38 +0100 Subject: [PATCH 01/42] Merge when build succeeds --- CHANGELOG | 1 + .../stylesheets/pages/merge_requests.scss | 4 +- .../projects/merge_requests_controller.rb | 35 ++++++++++++--- app/models/ci/commit.rb | 8 ++++ app/models/commit_status.rb | 33 ++++++++++++++ app/models/merge_request.rb | 13 ++++++ .../merge_when_build_succeeds_service.rb | 43 +++++++++++++++++++ .../merge_requests/refresh_service.rb | 8 +++- app/services/system_note_service.rb | 14 ++++++ .../cancel_merge_when_build_succeeds.js.haml | 2 + .../projects/merge_requests/merge.js.haml | 6 ++- .../merge_requests/widget/_open.html.haml | 2 + .../widget/open/_accept.html.haml | 18 +++++--- .../open/_merge_when_build_succeeds.html.haml | 27 ++++++++++++ config/routes.rb | 1 + ...ge_when_build_succeeds_to_merge_request.rb | 7 +++ db/schema.rb | 17 +++++--- 17 files changed, 219 insertions(+), 20 deletions(-) create mode 100644 app/services/merge_requests/merge_when_build_succeeds_service.rb create mode 100644 app/views/projects/merge_requests/cancel_merge_when_build_succeeds.js.haml create mode 100644 app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml create mode 100644 db/migrate/20151028152939_add_merge_when_build_succeeds_to_merge_request.rb diff --git a/CHANGELOG b/CHANGELOG index 0d89fca9fc..195e53abd8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ v 8.2.0 (unreleased) - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu) - Remove deprecated CI events from project settings page - Use issue editor as cross reference comment author when issue is edited with a new mention. + - Merge when build succeeds (Zeger-Jan van de Weg) v 8.1.1 - Fix cloning Wiki repositories via HTTP (Stan Hu) diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index f0b3667acc..b5a8c89367 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -19,18 +19,20 @@ .accept-merge-holder { .accept-action { display: inline-block; + float: left; } .accept-control { display: inline-block; + float: left; margin: 0; margin-left: 20px; padding: 5px; + padding-top: 12px; line-height: 20px; &.right { float: right; - padding-top: 12px; a { color: $gl-gray; } diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 16c4238662..2f9b8a25ed 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -2,7 +2,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController before_action :module_enabled before_action :merge_request, only: [ :edit, :update, :show, :diffs, :commits, :merge, :merge_check, - :ci_status, :toggle_subscription + :ci_status, :toggle_subscription, :cancel_merge_when_build_succeeds ] before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits] before_action :validates_merge_request, only: [:show, :diffs, :commits] @@ -149,15 +149,34 @@ class Projects::MergeRequestsController < Projects::ApplicationController render partial: "projects/merge_requests/widget/show.html.haml", layout: false end + def cancel_merge_when_build_succeeds + return access_denied! unless @merge_request.can_be_merged_by?(current_user) + + if @merge_request.merge_when_build_succeeds? + @merge_request.reset_merge_when_build_succeeds + SystemNoteService.cancel_merge_when_build_succeeds(merge_request, @project, @current_user) + end + end + def merge return access_denied! unless @merge_request.can_be_merged_by?(current_user) - if @merge_request.mergeable? - @merge_request.update(merge_error: nil) - MergeWorker.perform_async(@merge_request.id, current_user.id, params) - @status = true + unless @merge_request.mergeable? + @status = :failed + return + end + + @merge_request.update(merge_error: nil) + + if params[:merge_when_build_succeeds] && @merge_request.ci_commit.active? + MergeRequests::MergeWhenBuildSucceedsService.new(@project, + current_user, + merge_params: merge_params) + .execute(@merge_request) + @status = :merge_when_build_succeeds else - @status = false + MergeWorker.perform_async(@merge_request.id, current_user.id, params) + @status = :success end end @@ -282,6 +301,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController ) end + def merge_params + params.permit(:should_remove_source_branch, :commit_message) + end + # Make sure merge requests created before 8.0 # have head file in refs/merge-requests/ def ensure_ref_fetched diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb index 13437b2483..ebe4bace3b 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -164,6 +164,14 @@ module Ci status == 'canceled' end + def active? + running? || pending? + end + + def complete? + canceled? || success? || failed? + end + def duration duration_array = latest_statuses.map(&:duration).compact duration_array.reduce(:+).to_i diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 0b73ab6d2e..b1049fab78 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -1,3 +1,32 @@ +# == Schema Information +# +# project_id integer +# status string +# finished_at datetime +# trace text +# created_at datetime +# updated_at datetime +# started_at datetime +# runner_id integer +# coverage float +# commit_id integer +# commands text +# job_id integer +# name string +# deploy boolean default: false +# options text +# allow_failure boolean default: false, null: false +# stage string +# trigger_request_id integer +# stage_idx integer +# tag boolean +# ref string +# user_id integer +# type string +# target_url string +# description string +# + class CommitStatus < ActiveRecord::Base self.table_name = 'ci_builds' @@ -46,6 +75,10 @@ class CommitStatus < ActiveRecord::Base build.update_attributes finished_at: Time.now end + after_transition running: :success do |build, transition| + MergeRequests::MergeWhenBuildSucceedsService.new(build.commit.gl_project, nil).trigger(build) + end + state :pending, value: 'pending' state :running, value: 'running' state :failed, value: 'failed' diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 85f37e49e6..c5f04dbcf4 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -34,9 +34,12 @@ class MergeRequest < ActiveRecord::Base belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project" belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" + belongs_to :merge_user, class_name: "User" has_one :merge_request_diff, dependent: :destroy + serialize :merge_params, Hash + after_create :create_merge_request_diff after_update :update_merge_request_diff @@ -385,6 +388,16 @@ class MergeRequest < ActiveRecord::Base message end + def reset_merge_when_build_succeeds + return unless merge_when_build_succeeds? + + self.merge_when_build_succeeds = false + self.merge_user = nil + self.merge_params = nil + + self.save + end + # Return array of possible target branches # depends on target project of MR def target_branches diff --git a/app/services/merge_requests/merge_when_build_succeeds_service.rb b/app/services/merge_requests/merge_when_build_succeeds_service.rb new file mode 100644 index 0000000000..a4418360b8 --- /dev/null +++ b/app/services/merge_requests/merge_when_build_succeeds_service.rb @@ -0,0 +1,43 @@ +module MergeRequests + class MergeWhenBuildSucceedsService < MergeRequests::BaseService + def execute(merge_request) + merge_request.merge_params.merge!(params[:merge_params]) + + # The service is also called when the merge params are updated. + already_approved = merge_request.merge_when_build_succeeds? + + unless already_approved + merge_request.merge_when_build_succeeds = true + merge_request.merge_user = @current_user + end + + merge_request.save + + unless already_approved + SystemNoteService.merge_when_build_succeeds(merge_request, @project, @current_user) + end + end + + def trigger(build) + merge_requests = merge_request_from(build) + + merge_requests.each do |merge_request| + next unless merge_request.merge_when_build_succeeds? + + ci_commit = merge_request.ci_commit + if ci_commit && ci_commit.success? && merge_request.mergeable? + MergeWorker.perform_async(merge_request.id, merge_request.merge_user_id, merge_request.merge_params) + end + end + end + + private + + def merge_request_from(build) + merge_requests = @project.origin_merge_requests.opened.where(source_branch: build.ref).to_a + merge_requests += @project.fork_merge_requests.opened.where(source_branch: build.ref).to_a + + merge_requests.uniq.select(&:source_project) + end + end +end diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index d68bc79ecc..335ef32abc 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -8,6 +8,7 @@ module MergeRequests find_new_commits reload_merge_requests + reset_merge_when_build_succeeds # Leave a system note if a branch was deleted/added if branch_added? || branch_removed? @@ -57,7 +58,6 @@ module MergeRequests merge_requests = filter_merge_requests(merge_requests) merge_requests.each do |merge_request| - if merge_request.source_branch == @branch_name || force_push? merge_request.reload_code merge_request.mark_as_unchecked @@ -76,6 +76,12 @@ module MergeRequests end end + def reset_merge_when_build_succeeds + merge_requests_for_source_branch.each do |merge_request| + merge_request.reset_merge_when_build_succeeds + end + end + def find_new_commits if branch_added? @commits = [] diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 708c2f0048..c9846e9f26 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -130,6 +130,20 @@ class SystemNoteService create_note(noteable: noteable, project: project, author: author, note: body) end + # Called when 'merge when build succeeds' is executed + def self.merge_when_build_succeeds(noteable, project, author) + body = "Approved this request to be merged automatically when the build succeeds" + + create_note(noteable: noteable, project: project, author: author, note: body) + end + + # Called when 'merge when build succeeds' is canceled + def self.cancel_merge_when_build_succeeds(noteable, project, author) + body = "Canceled the automatic merge" + + create_note(noteable: noteable, project: project, author: author, note: body) + end + # Called when the title of a Noteable is changed # # noteable - Noteable object that responds to `title` diff --git a/app/views/projects/merge_requests/cancel_merge_when_build_succeeds.js.haml b/app/views/projects/merge_requests/cancel_merge_when_build_succeeds.js.haml new file mode 100644 index 0000000000..eab5be488b --- /dev/null +++ b/app/views/projects/merge_requests/cancel_merge_when_build_succeeds.js.haml @@ -0,0 +1,2 @@ +:plain + $('.mr-widget-body').html("#{escape_javascript(render('projects/merge_requests/widget/open/accept'))}"); diff --git a/app/views/projects/merge_requests/merge.js.haml b/app/views/projects/merge_requests/merge.js.haml index 33321651e3..89aae17a60 100644 --- a/app/views/projects/merge_requests/merge.js.haml +++ b/app/views/projects/merge_requests/merge.js.haml @@ -1,6 +1,10 @@ -- if @status +- case @status +- when :success :plain merge_request_widget.mergeInProgress(); +- when :merge_when_build_succeeds + :plain + $('.mr-widget-body').html("#{escape_javascript(render('projects/merge_requests/widget/open/merge_when_build_succeeds'))}"); - else :plain $('.mr-widget-body').html("#{escape_javascript(render('projects/merge_requests/widget/open/reload'))}"); diff --git a/app/views/projects/merge_requests/widget/_open.html.haml b/app/views/projects/merge_requests/widget/_open.html.haml index 0aad9bb3e8..e0013fb769 100644 --- a/app/views/projects/merge_requests/widget/_open.html.haml +++ b/app/views/projects/merge_requests/widget/_open.html.haml @@ -13,6 +13,8 @@ = render 'projects/merge_requests/widget/open/conflicts' - elsif @merge_request.work_in_progress? = render 'projects/merge_requests/widget/open/wip' + - elsif @merge_request.merge_when_build_succeeds? + = render 'projects/merge_requests/widget/open/merge_when_build_succeeds' - elsif !@merge_request.can_be_merged_by?(current_user) = render 'projects/merge_requests/widget/open/not_allowed' - elsif @merge_request.can_be_merged? diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index 613525437a..2afc5f8125 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -2,8 +2,15 @@ = hidden_field_tag :authenticity_token, form_authenticity_token .accept-merge-holder.clearfix.js-toggle-container .accept-action - = f.button class: "btn btn-create accept_merge_request" do - Accept Merge Request + - ci_commit = @merge_request.ci_commit + - if ci_commit && ci_commit.active? + = f.button class: "btn btn-create btn-grouped merge_when_build_succeeds", name: "merge_when_build_succeeds" do + Merge when Build Succeeds + = f.button class: "btn btn-warning btn-grouped accept_merge_request" do + Accept Merge Request Now + - else + = f.button class: "btn btn-create btn-grouped accept_merge_request" do + Accept Merge Request - if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork? .accept-control.checkbox = label_tag :should_remove_source_branch, class: "remove_source_checkbox" do @@ -19,7 +26,8 @@ rows: 14, hint: true :coffeescript - $('.accept-mr-form').on 'ajax:before', -> - btn = $('.accept_merge_request') - btn.disable() + $('.accept_merge_request').on 'click', -> + btn = $(this) btn.html(" Merge in progress") + $('.accept-mr-form').on 'ajax:sen', -> + $(".accept-mr-form :input").disable() diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml new file mode 100644 index 0000000000..7e5385cf8b --- /dev/null +++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml @@ -0,0 +1,27 @@ +%h4 + Approved by #{link_to_member(@project, @merge_request.merge_user, avatar: true)} + to be merged automatically when + #{link_to "the build", ci_status_path(@merge_request.ci_commit)} succeeds +%div + - if @merge_request.merge_params["should_remove_source_branch"] + = succeed '.' do + The changes will be merged into + %span.label-branch= @merge_request.target_branch + The source branch will be removed. + - elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) + - remove_source_branch_button = true + %p + = succeed '.' do + The changes will be merged into + %span.label-branch= @merge_request.target_branch + The source branch will not be removed. + +- if remove_source_branch_button || @merge_request.can_be_merged_by?(current_user) + .clearfix.prepend-top-10 + - if remove_source_branch_button + = link_to merge_namespace_project_merge_request_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do + = icon('times') + Remove Source Branch When Merged + - if @merge_request.can_be_merged_by?(current_user) + = link_to merge_namespace_project_merge_request_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request), remote: true, method: :delete, class: "btn btn-grouped btn-warning btn-sm" do + Cancel Automatic Merge diff --git a/config/routes.rb b/config/routes.rb index 0458f538eb..917c3d3f1e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -556,6 +556,7 @@ Gitlab::Application.routes.draw do get :diffs get :commits post :merge + delete :merge, action: :cancel_merge_when_build_succeeds get :merge_check get :ci_status post :toggle_subscription diff --git a/db/migrate/20151028152939_add_merge_when_build_succeeds_to_merge_request.rb b/db/migrate/20151028152939_add_merge_when_build_succeeds_to_merge_request.rb new file mode 100644 index 0000000000..ceb52f0c22 --- /dev/null +++ b/db/migrate/20151028152939_add_merge_when_build_succeeds_to_merge_request.rb @@ -0,0 +1,7 @@ +class AddMergeWhenBuildSucceedsToMergeRequest < ActiveRecord::Migration + def change + add_column :merge_requests, :merge_params, :text + add_column :merge_requests, :merge_when_build_succeeds, :boolean, default: false, null: false + add_column :merge_requests, :merge_user_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 4bde9f0b74..825d95565b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151026182941) do +ActiveRecord::Schema.define(version: 20151028152939) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -418,6 +418,7 @@ ActiveRecord::Schema.define(version: 20151026182941) do end add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree + add_index "labels", ["title"], name: "index_labels_on_title", using: :btree create_table "members", force: true do |t| t.integer "access_level", null: false @@ -453,9 +454,9 @@ ActiveRecord::Schema.define(version: 20151026182941) do add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", unique: true, using: :btree create_table "merge_requests", force: true do |t| - t.string "target_branch", null: false - t.string "source_branch", null: false - t.integer "source_project_id", null: false + t.string "target_branch", null: false + t.string "source_branch", null: false + t.integer "source_project_id", null: false t.integer "author_id" t.integer "assignee_id" t.string "title" @@ -464,13 +465,16 @@ ActiveRecord::Schema.define(version: 20151026182941) do t.integer "milestone_id" t.string "state" t.string "merge_status" - t.integer "target_project_id", null: false + t.integer "target_project_id", null: false t.integer "iid" t.text "description" - t.integer "position", default: 0 + t.integer "position", default: 0 t.datetime "locked_at" t.integer "updated_by_id" t.string "merge_error" + t.text "merge_params" + t.boolean "merge_when_build_succeeds", default: false, null: false + t.integer "merge_user_id" end add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree @@ -499,6 +503,7 @@ ActiveRecord::Schema.define(version: 20151026182941) do add_index "milestones", ["due_date"], name: "index_milestones_on_due_date", using: :btree add_index "milestones", ["project_id", "iid"], name: "index_milestones_on_project_id_and_iid", unique: true, using: :btree add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree + add_index "milestones", ["title"], name: "index_milestones_on_title", using: :btree create_table "namespaces", force: true do |t| t.string "name", null: false From 63b234706d46f75c0c0f93bdfdc576e328981eb5 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 2 Nov 2015 20:02:51 +0100 Subject: [PATCH 02/42] MRs author can cancel automatic merge --- app/controllers/projects/merge_requests_controller.rb | 4 +++- .../widget/open/_merge_when_build_succeeds.html.haml | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 2f9b8a25ed..d58dab2d66 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -150,7 +150,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController end def cancel_merge_when_build_succeeds - return access_denied! unless @merge_request.can_be_merged_by?(current_user) + unless @merge_request.can_be_merged_by?(current_user) || @merge_request.author == current_user + return access_denied! + end if @merge_request.merge_when_build_succeeds? @merge_request.reset_merge_when_build_succeeds diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml index 7e5385cf8b..f389433496 100644 --- a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml +++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml @@ -14,7 +14,7 @@ = succeed '.' do The changes will be merged into %span.label-branch= @merge_request.target_branch - The source branch will not be removed. + The source branch won't be removed. - if remove_source_branch_button || @merge_request.can_be_merged_by?(current_user) .clearfix.prepend-top-10 @@ -22,6 +22,6 @@ = link_to merge_namespace_project_merge_request_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do = icon('times') Remove Source Branch When Merged - - if @merge_request.can_be_merged_by?(current_user) + - if @merge_request.can_be_merged_by?(current_user) || @merge_request.author == current_user = link_to merge_namespace_project_merge_request_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request), remote: true, method: :delete, class: "btn btn-grouped btn-warning btn-sm" do Cancel Automatic Merge From 2f048df4a4a83ff009d2ef2d14ee04e5a2798618 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Wed, 18 Nov 2015 11:17:41 +0100 Subject: [PATCH 03/42] API support, incorporated feedback --- .../projects/merge_requests_controller.rb | 4 +- app/models/commit_status.rb | 2 +- app/models/merge_request.rb | 6 +- app/services/merge_requests/merge_service.rb | 16 +++-- .../merge_when_build_succeeds_service.rb | 2 +- .../merge_requests/refresh_service.rb | 4 +- app/services/system_note_service.rb | 2 +- .../widget/open/_accept.html.haml | 2 +- .../open/_merge_when_build_succeeds.html.haml | 8 +-- app/workers/merge_worker.rb | 13 +--- config/routes.rb | 3 +- doc/api/merge_requests.md | 60 ++++++++++++++-- lib/api/merge_requests.rb | 68 +++++++++++++------ spec/models/merge_request_spec.rb | 14 +++- spec/services/system_note_service_spec.rb | 16 +++++ 15 files changed, 157 insertions(+), 63 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index d58dab2d66..931298df5d 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -171,9 +171,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.update(merge_error: nil) if params[:merge_when_build_succeeds] && @merge_request.ci_commit.active? - MergeRequests::MergeWhenBuildSucceedsService.new(@project, - current_user, - merge_params: merge_params) + MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params) .execute(@merge_request) @status = :merge_when_build_succeeds else diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index b1049fab78..acc86b1a8c 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -75,7 +75,7 @@ class CommitStatus < ActiveRecord::Base build.update_attributes finished_at: Time.now end - after_transition running: :success do |build, transition| + after_transition [:pending, :running] => :success do |build, transition| MergeRequests::MergeWhenBuildSucceedsService.new(build.commit.gl_project, nil).trigger(build) end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index c5f04dbcf4..7b372399a3 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -253,6 +253,10 @@ class MergeRequest < ActiveRecord::Base end end + def mergeable_by_or_author(user) + self.can_be_merged_by?(user) || self.author == user + end + def mr_and_commit_notes # Fetch comments only from last 100 commits commits_for_notes_limit = 100 @@ -390,7 +394,7 @@ class MergeRequest < ActiveRecord::Base def reset_merge_when_build_succeeds return unless merge_when_build_succeeds? - + self.merge_when_build_succeeds = false self.merge_user = nil self.merge_params = nil diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 7963af127e..db8d18a7d8 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -6,15 +6,12 @@ module MergeRequests # Executed when you do merge via GitLab UI # class MergeService < MergeRequests::BaseService - attr_reader :merge_request, :commit_message + attr_reader :merge_request - def execute(merge_request, commit_message) - @commit_message = commit_message + def execute(merge_request) @merge_request = merge_request - unless @merge_request.mergeable? - return error('Merge request is not mergeable') - end + return error('Merge request is not mergeable') unless @merge_request.mergeable? merge_request.in_locked_state do if commit @@ -32,7 +29,7 @@ module MergeRequests committer = repository.user_to_committer(current_user) options = { - message: commit_message, + message: params[:commit_message] || merge_request.merge_commit_message, author: committer, committer: committer } @@ -46,6 +43,11 @@ module MergeRequests def after_merge MergeRequests::PostMergeService.new(project, current_user).execute(merge_request) + + if params[:should_remove_source_branch] + DeleteBranchService.new(@merge_request.source_project, current_user). + execute(merge_request.source_branch) + end end end end diff --git a/app/services/merge_requests/merge_when_build_succeeds_service.rb b/app/services/merge_requests/merge_when_build_succeeds_service.rb index a4418360b8..d5cae2f98f 100644 --- a/app/services/merge_requests/merge_when_build_succeeds_service.rb +++ b/app/services/merge_requests/merge_when_build_succeeds_service.rb @@ -1,7 +1,7 @@ module MergeRequests class MergeWhenBuildSucceedsService < MergeRequests::BaseService def execute(merge_request) - merge_request.merge_params.merge!(params[:merge_params]) + merge_request.merge_params.merge!(params) # The service is also called when the merge params are updated. already_approved = merge_request.merge_when_build_succeeds? diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index 335ef32abc..e502485720 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -77,9 +77,7 @@ module MergeRequests end def reset_merge_when_build_succeeds - merge_requests_for_source_branch.each do |merge_request| - merge_request.reset_merge_when_build_succeeds - end + merge_requests_for_source_branch.each(&:reset_merge_when_build_succeeds) end def find_new_commits diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index c9846e9f26..5e8281a3fd 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -132,7 +132,7 @@ class SystemNoteService # Called when 'merge when build succeeds' is executed def self.merge_when_build_succeeds(noteable, project, author) - body = "Approved this request to be merged automatically when the build succeeds" + body = "This merge request will be automatically merged when the build for #{noteable.ci_commit.short_sha} succeeds" create_note(noteable: noteable, project: project, author: author, note: body) end diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index 2afc5f8125..2a51241971 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -29,5 +29,5 @@ $('.accept_merge_request').on 'click', -> btn = $(this) btn.html(" Merge in progress") - $('.accept-mr-form').on 'ajax:sen', -> + $('.accept-mr-form').on 'ajax:send', -> $(".accept-mr-form :input").disable() diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml index f389433496..ddd1a7bd63 100644 --- a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml +++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml @@ -1,9 +1,9 @@ %h4 Approved by #{link_to_member(@project, @merge_request.merge_user, avatar: true)} to be merged automatically when - #{link_to "the build", ci_status_path(@merge_request.ci_commit)} succeeds + #{link_to "the build", ci_status_path(@merge_request.ci_commit)} succeeds. %div - - if @merge_request.merge_params["should_remove_source_branch"] + - if @merge_request.merge_params["should_remove_source_branch"].present? = succeed '.' do The changes will be merged into %span.label-branch= @merge_request.target_branch @@ -19,9 +19,9 @@ - if remove_source_branch_button || @merge_request.can_be_merged_by?(current_user) .clearfix.prepend-top-10 - if remove_source_branch_button - = link_to merge_namespace_project_merge_request_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do + = link_to merge_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do = icon('times') Remove Source Branch When Merged - if @merge_request.can_be_merged_by?(current_user) || @merge_request.author == current_user - = link_to merge_namespace_project_merge_request_path(@merge_request.source_project.namespace, @merge_request.source_project, @merge_request), remote: true, method: :delete, class: "btn btn-grouped btn-warning btn-sm" do + = link_to cancel_merge_when_build_succeeds_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request), remote: true, method: :post, class: "btn btn-grouped btn-warning btn-sm" do Cancel Automatic Merge diff --git a/app/workers/merge_worker.rb b/app/workers/merge_worker.rb index 5d1a8555b7..c87c0a252b 100644 --- a/app/workers/merge_worker.rb +++ b/app/workers/merge_worker.rb @@ -8,16 +8,7 @@ class MergeWorker current_user = User.find(current_user_id) merge_request = MergeRequest.find(merge_request_id) - result = MergeRequests::MergeService.new(merge_request.target_project, current_user). - execute(merge_request, params[:commit_message]) - - if result[:status] == :success && params[:should_remove_source_branch].present? - DeleteBranchService.new(merge_request.source_project, current_user). - execute(merge_request.source_branch) - - merge_request.source_project.repository.expire_branch_names - end - - result + MergeRequests::MergeService.new(merge_request.target_project, current_user, params). + execute(merge_request) end end diff --git a/config/routes.rb b/config/routes.rb index 917c3d3f1e..993687665c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -556,8 +556,7 @@ Gitlab::Application.routes.draw do get :diffs get :commits post :merge - delete :merge, action: :cancel_merge_when_build_succeeds - get :merge_check + post :cancel_merge_when_build_succeeds get :ci_status post :toggle_subscription end diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index ffa7f2cdf1..1b2ad1caf4 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -2,8 +2,8 @@ ## List merge requests -Get all merge requests for this project. -The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`). +Get all merge requests for this project. +The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`). The pagination parameters `page` and `per_page` can be used to restrict the list of merge requests. ``` @@ -292,9 +292,59 @@ PUT /projects/:id/merge_request/:merge_request_id/merge Parameters: -- `id` (required) - The ID of a project -- `merge_request_id` (required) - ID of MR -- `merge_commit_message` (optional) - Custom merge commit message +- `id` (required) - The ID of a project +- `merge_request_id` (required) - ID of MR +- `merge_commit_message` (optional) - Custom merge commit message +- `should_remove_source_branch` (optional) - if `true` removes the source branch +- `merge_when_build_succeeds` (optional) - if `true` the MR is merge when the build succeeds + +```json +{ + "id": 1, + "target_branch": "master", + "source_branch": "test1", + "project_id": 3, + "title": "test1", + "state": "merged", + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1, + "username": "admin", + "email": "admin@example.com", + "name": "Administrator", + "state": "active", + "created_at": "2012-04-29T08:46:00Z" + }, + "assignee": { + "id": 1, + "username": "admin", + "email": "admin@example.com", + "name": "Administrator", + "state": "active", + "created_at": "2012-04-29T08:46:00Z" + } +} +``` + +## Cancel Merge When Build Succeeds + +Cancels the merge when build succeeds and reset the merge parameters + +If successfull you'll get `200 OK`. + +If you don't have permissions to accept this merge request - you'll get a 401 + +If the merge request is already merged or closed - you get 405 and error message 'Method Not Allowed' + +In case the merge request is not set to be merged when the build succeeds, you'll also get a 405 with the error message 'Method Not Allowed' +``` +PUT /projects/:id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds +``` +Parameters: + +- `id` (required) - The ID of a project +- `merge_request_id` (required) - ID of MR ```json { diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 6eb84baf9c..f981432db3 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -179,9 +179,10 @@ module API # Merge MR # # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - ID of MR - # merge_commit_message (optional) - Custom merge commit message + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # merge_commit_message (optional) - Custom merge commit message + # merge_when_build_succeeds (optional) - truethy when this MR should be merged when the build is succesfull # Example: # PUT /projects/:id/merge_request/:merge_request_id/merge # @@ -191,34 +192,57 @@ module API allowed = ::Gitlab::GitAccess.new(current_user, user_project). can_push_to_branch?(merge_request.target_branch) - if allowed - if merge_request.unchecked? - merge_request.check_if_can_be_merged - end + # Merge request can not be merged + # because user dont have permissions to push into target branch + unauthorized! unless allowed - if merge_request.open? && !merge_request.work_in_progress? - if merge_request.can_be_merged? - commit_message = params[:merge_commit_message] || merge_request.merge_commit_message + not_allowed! unless merge_request.open? - ::MergeRequests::MergeService.new(merge_request.target_project, current_user). - execute(merge_request, commit_message) + merge_request.check_if_can_be_merged if merge_request.unchecked? - present merge_request, with: Entities::MergeRequest - else - render_api_error!('Branch cannot be merged', 405) - end + merge_params = { + commit_message: params[:merge_commit_message], + should_remove_source_branch: params[:should_remove_source_branch] + } + + if !merge_request.work_in_progress? + if parse_boolean(params[:merge_when_build_succeeds]) + ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). + execute(merge_request) else - # Merge request can not be merged - # because it is already closed/merged or marked as WIP - not_allowed! + ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params). + execute(merge_request, merge_params) end else - # Merge request can not be merged - # because user dont have permissions to push into target branch - unauthorized! + render_api_error!('Branch cannot be merged', 405) end + + present merge_request, with: Entities::MergeRequest end + # Cancel Merge if Merge When build succeeds is enabled + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # + post ":id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds" do + merge_request = user_project.merge_requests.find(params[:merge_request_id]) + + allowed = ::Gitlab::GitAccess.new(current_user, user_project). + can_push_to_branch?(merge_request.target_branch) + + # Merge request can not be merged + # because user dont have permissions to push into target branch + unauthorized! unless allowed + + if merge_request.merged? || !merge_request.open? || !merge_request.merge_when_build_succeeds? + not_allowed! + end + + merge_request.reset_merge_when_build_succeeds + + present merge_request, with: Entities::MergeRequest + end # Get a merge request's comments # diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index eed2cbc541..e42534a849 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -30,7 +30,7 @@ describe MergeRequest do describe 'associations' do it { is_expected.to belong_to(:target_project).with_foreign_key(:target_project_id).class_name('Project') } it { is_expected.to belong_to(:source_project).with_foreign_key(:source_project_id).class_name('Project') } - + it { is_expected.to belong_to(:merge_user).class_name("User") } it { is_expected.to have_one(:merge_request_diff).dependent(:destroy) } end @@ -53,6 +53,8 @@ describe MergeRequest do it { is_expected.to respond_to(:unchecked?) } it { is_expected.to respond_to(:can_be_merged?) } it { is_expected.to respond_to(:cannot_be_merged?) } + it { is_expected.to respond_to(:merge_params) } + it { is_expected.to respond_to(:merge_when_build_succeeds) } end describe '#to_reference' do @@ -171,6 +173,16 @@ describe MergeRequest do end end + describe "#reset_merge_when_build_succeeds" do + let(:merge_if_green) { create :merge_request, merge_when_build_succeeds: true } + it "sets the item to false" do + merge_if_green.reset_merge_when_build_succeeds + merge_if_green.reload + + expect(merge_if_green.merge_when_build_succeeds).to be_falsey + end + end + describe "#hook_attrs" do it "has all the required keys" do attrs = subject.hook_attrs diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index a45130bd47..35912ece64 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -207,6 +207,22 @@ describe SystemNoteService do end end + describe '.merge_when_build_succeeds' do + let(:ci_commit) { create :ci_commit, gl_project: project } + let(:merge_request) { create :merge_request, project: project } + + subject { described_class.merge_when_build_succeeds(merge_request, project, author) } + + it_behaves_like 'a system note' + + it "posts the Merge When Build Succeeds system note" do + allow(merge_request).to receive(:ci_commit).and_return(ci_commit) + allow(ci_commit).to receive(:short_sha).and_return('12345678') + + expect(subject.note).to eq "This merge request will be automatically merged when the build for 12345678 succeeds" + end + end + describe '.change_title' do subject { described_class.change_title(noteable, project, author, 'Old title') } From 8608c6325e19f529f7b43ff881c562d3a0114e1c Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 23 Nov 2015 09:42:20 +0100 Subject: [PATCH 04/42] Refactor MergeWhenBuildSucceedsService and incorporate feedback --- CHANGELOG | 5 +-- .../projects/merge_requests_controller.rb | 11 ++---- app/models/merge_request.rb | 11 ++++-- .../merge_when_build_succeeds_service.rb | 17 ++++++++- app/services/system_note_service.rb | 4 +-- .../widget/open/_accept.html.haml | 2 +- .../open/_merge_when_build_succeeds.html.haml | 9 ++--- config/routes.rb | 1 + db/schema.rb | 2 -- doc/api/merge_requests.md | 8 ++--- lib/api/merge_requests.rb | 36 +++++++------------ 11 files changed, 52 insertions(+), 54 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 08188324d7..18f5f270ec 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.3.0 (unreleased) +- Merge when build succeeds (Zeger-Jan van de Weg) v 8.2.0 - Fix grouping of contributors by email in graph. @@ -28,10 +29,6 @@ v 8.2.0 - Allow to define cache in `.gitlab-ci.yml` - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu) - Remove deprecated CI events from project settings page - - Use issue editor as cross reference comment author when issue is edited with a new mention. - - Merge when build succeeds (Zeger-Jan van de Weg) - -v 8.1.1 - [API] Add ability to fetch the commit ID of the last commit that actually touched a file - Fix omniauth documentation setting for omnibus configuration (Jon Cairns) - Add "New file" link to dropdown on project page diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 9db6ed5022..f2e9a34dd2 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -151,14 +151,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController end def cancel_merge_when_build_succeeds - unless @merge_request.can_be_merged_by?(current_user) || @merge_request.author == current_user - return access_denied! - end + return access_denied! unless @merge_request.can_cancel_merge_when_build_succeeds?(current_user) - if @merge_request.merge_when_build_succeeds? - @merge_request.reset_merge_when_build_succeeds - SystemNoteService.cancel_merge_when_build_succeeds(merge_request, @project, @current_user) - end + MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user).cancel(@merge_request) end def merge @@ -171,7 +166,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.update(merge_error: nil) - if params[:merge_when_build_succeeds] && @merge_request.ci_commit.active? + if params[:merge_when_build_succeeds] && @merge_request.ci_commit && @merge_request.ci_commit.active? MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params) .execute(@merge_request) @status = :merge_when_build_succeeds diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 05c3bc074b..89f9e8fa6a 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -254,8 +254,15 @@ class MergeRequest < ActiveRecord::Base end end - def mergeable_by_or_author(user) - self.can_be_merged_by?(user) || self.author == user + def can_cancel_merge_when_build_succeeds?(user) + can_be_merged_by?(user) || self.author == user + end + + def can_remove_source_branch? + for_fork? && + !project.protected_branch(source_branch) && + !project.repository.root_ref(source_branch) && + can?(current_user, :push_code, project) end def mr_and_commit_notes diff --git a/app/services/merge_requests/merge_when_build_succeeds_service.rb b/app/services/merge_requests/merge_when_build_succeeds_service.rb index d5cae2f98f..15dcace5df 100644 --- a/app/services/merge_requests/merge_when_build_succeeds_service.rb +++ b/app/services/merge_requests/merge_when_build_succeeds_service.rb @@ -1,5 +1,7 @@ module MergeRequests class MergeWhenBuildSucceedsService < MergeRequests::BaseService + # Marks the passed `merge_request` to be marked when the build succeeds or + # updates the params for the automatic merge def execute(merge_request) merge_request.merge_params.merge!(params) @@ -14,10 +16,11 @@ module MergeRequests merge_request.save unless already_approved - SystemNoteService.merge_when_build_succeeds(merge_request, @project, @current_user) + SystemNoteService.merge_when_build_succeeds(merge_request, @project, @current_user, merge_request.ci_commit) end end + # Triggers the automatic merge of merge_request once the build succeeds def trigger(build) merge_requests = merge_request_from(build) @@ -31,6 +34,18 @@ module MergeRequests end end + # Cancels the automatic merge + def cancel(merge_request) + if merge_request.merge_when_build_succeeds? && merge_request.open? && !merge_request.merged? + merge_request.reset_merge_when_build_succeeds + SystemNoteService.cancel_merge_when_build_succeeds(merge_request, @project, @current_user) + + success + else + error("Can't cancel the automatic merge", 406) + end + end + private def merge_request_from(build) diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 5e8281a3fd..7de4221c4c 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -131,8 +131,8 @@ class SystemNoteService end # Called when 'merge when build succeeds' is executed - def self.merge_when_build_succeeds(noteable, project, author) - body = "This merge request will be automatically merged when the build for #{noteable.ci_commit.short_sha} succeeds" + def self.merge_when_build_succeeds(noteable, project, author, ci_commit) + body = "Approved an automatic merge when the build for #{ci_commit.sha} succeeds" create_note(noteable: noteable, project: project, author: author, note: body) end diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index d2189787d4..5ec623b472 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -13,7 +13,7 @@ - else = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do Accept Merge Request - - if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork? + - if @merge_request.can_remove_source_branch? .accept-control.checkbox = label_tag :should_remove_source_branch, class: "remove_source_checkbox" do = check_box_tag :should_remove_source_branch diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml index ddd1a7bd63..51e18f8442 100644 --- a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml +++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml @@ -8,20 +8,17 @@ The changes will be merged into %span.label-branch= @merge_request.target_branch The source branch will be removed. - - elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) - - remove_source_branch_button = true %p = succeed '.' do The changes will be merged into %span.label-branch= @merge_request.target_branch - The source branch won't be removed. + The source branch will not be removed. -- if remove_source_branch_button || @merge_request.can_be_merged_by?(current_user) .clearfix.prepend-top-10 - - if remove_source_branch_button + - if @merge_request.can_remove_source_branch? && !@merge_request.merge_params["should_remove_source_branch"].present? = link_to merge_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do = icon('times') Remove Source Branch When Merged - - if @merge_request.can_be_merged_by?(current_user) || @merge_request.author == current_user + - if @merge_request.merge_when_build_succeeds = link_to cancel_merge_when_build_succeeds_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request), remote: true, method: :post, class: "btn btn-grouped btn-warning btn-sm" do Cancel Automatic Merge diff --git a/config/routes.rb b/config/routes.rb index 4954378668..81f568cfa7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -570,6 +570,7 @@ Gitlab::Application.routes.draw do member do get :diffs get :commits + get :merge_check post :merge post :cancel_merge_when_build_succeeds get :ci_status diff --git a/db/schema.rb b/db/schema.rb index fa32617cb9..7d5ed55975 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -421,7 +421,6 @@ ActiveRecord::Schema.define(version: 20151116144118) do end add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree - add_index "labels", ["title"], name: "index_labels_on_title", using: :btree create_table "lfs_objects", force: true do |t| t.string "oid", null: false @@ -525,7 +524,6 @@ ActiveRecord::Schema.define(version: 20151116144118) do add_index "milestones", ["due_date"], name: "index_milestones_on_due_date", using: :btree add_index "milestones", ["project_id", "iid"], name: "index_milestones_on_project_id_and_iid", unique: true, using: :btree add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree - add_index "milestones", ["title"], name: "index_milestones_on_title", using: :btree create_table "namespaces", force: true do |t| t.string "name", null: false diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 1b2ad1caf4..19e6fbb788 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -296,7 +296,7 @@ Parameters: - `merge_request_id` (required) - ID of MR - `merge_commit_message` (optional) - Custom merge commit message - `should_remove_source_branch` (optional) - if `true` removes the source branch -- `merge_when_build_succeeds` (optional) - if `true` the MR is merge when the build succeeds +- `merged_when_build_succeeds` (optional) - if `true` the MR is merge when the build succeeds ```json { @@ -329,15 +329,13 @@ Parameters: ## Cancel Merge When Build Succeeds -Cancels the merge when build succeeds and reset the merge parameters - -If successfull you'll get `200 OK`. +If successful you'll get `200 OK`. If you don't have permissions to accept this merge request - you'll get a 401 If the merge request is already merged or closed - you get 405 and error message 'Method Not Allowed' -In case the merge request is not set to be merged when the build succeeds, you'll also get a 405 with the error message 'Method Not Allowed' +In case the merge request is not set to be merged when the build succeeds, you'll also get a 406 error. ``` PUT /projects/:id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds ``` diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index f981432db3..b72f816932 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -182,39 +182,35 @@ module API # id (required) - The ID of a project # merge_request_id (required) - ID of MR # merge_commit_message (optional) - Custom merge commit message - # merge_when_build_succeeds (optional) - truethy when this MR should be merged when the build is succesfull + # should_remove_source_branch - When true, the source branch will be deleted if possible + # merge_when_build_succeeds (optional) - When true, this MR will be merged when the build succeeds # Example: # PUT /projects/:id/merge_request/:merge_request_id/merge # put ":id/merge_request/:merge_request_id/merge" do merge_request = user_project.merge_requests.find(params[:merge_request_id]) - allowed = ::Gitlab::GitAccess.new(current_user, user_project). - can_push_to_branch?(merge_request.target_branch) - # Merge request can not be merged # because user dont have permissions to push into target branch - unauthorized! unless allowed + unauthorized! unless merge_request.can_be_merged_by?(current_user) - not_allowed! unless merge_request.open? + not_allowed! unless merge_request.open? && !merge_request.work_in_progress? merge_request.check_if_can_be_merged if merge_request.unchecked? + render_api_error!('Branch cannot be merged', 406) if merge_request.can_be_merged? + merge_params = { commit_message: params[:merge_commit_message], should_remove_source_branch: params[:should_remove_source_branch] } - if !merge_request.work_in_progress? - if parse_boolean(params[:merge_when_build_succeeds]) - ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). - execute(merge_request) - else - ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params). - execute(merge_request, merge_params) - end + if parse_boolean(params[:merge_when_build_succeeds]) && merge_request.ci_commit && merge_request.ci_commit.active? + ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). + execute(merge_request) else - render_api_error!('Branch cannot be merged', 405) + ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params). + execute(merge_request) end present merge_request, with: Entities::MergeRequest @@ -233,15 +229,9 @@ module API # Merge request can not be merged # because user dont have permissions to push into target branch - unauthorized! unless allowed + unauthorized! unless merge_request.can_cancel_merge_when_build_succeeds?(current_user) - if merge_request.merged? || !merge_request.open? || !merge_request.merge_when_build_succeeds? - not_allowed! - end - - merge_request.reset_merge_when_build_succeeds - - present merge_request, with: Entities::MergeRequest + ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user).cancel(merge_request) end # Get a merge request's comments From a7682f8775a4609ac8c70151ffe8f3ccf3b767b6 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Tue, 24 Nov 2015 14:59:02 +0100 Subject: [PATCH 05/42] Specs for 'Merge When Build Succeeds' --- .gitignore | 1 + app/models/merge_request.rb | 13 ++- .../merge_when_build_succeeds_service.rb | 6 +- app/services/system_note_service.rb | 2 +- .../merge_requests/widget/_merged.html.haml | 4 +- .../widget/open/_accept.html.haml | 4 +- .../open/_merge_when_build_succeeds.html.haml | 21 ++--- lib/api/entities.rb | 1 + lib/api/merge_requests.rb | 22 ++--- spec/factories/ci/commits.rb | 23 +++--- spec/factories/commit_statuses.rb | 2 +- .../merge_when_build_succeeds_spec.rb | 80 +++++++++++++++++++ spec/models/merge_request_spec.rb | 24 ++++++ spec/requests/api/merge_requests_spec.rb | 17 +++- .../merge_requests/merge_service_spec.rb | 8 +- .../merge_when_build_succeeds_service_spec.rb | 78 ++++++++++++++++++ .../merge_requests/refresh_service_spec.rb | 5 +- spec/services/system_note_service_spec.rb | 22 +++-- 18 files changed, 268 insertions(+), 65 deletions(-) create mode 100644 spec/features/merge_requests/merge_when_build_succeeds_spec.rb create mode 100644 spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb diff --git a/.gitignore b/.gitignore index f5b6427ca0..881b3fb81a 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ public/assets/ public/uploads.* public/uploads/ shared/artifacts/ +TODO rails_best_practices_output.html /tags tmp/ diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 89f9e8fa6a..131dfda6b5 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -254,15 +254,14 @@ class MergeRequest < ActiveRecord::Base end end - def can_cancel_merge_when_build_succeeds?(user) - can_be_merged_by?(user) || self.author == user + def can_cancel_merge_when_build_succeeds?(current_user) + can_be_merged_by?(current_user) || self.author == current_user end - def can_remove_source_branch? - for_fork? && - !project.protected_branch(source_branch) && - !project.repository.root_ref(source_branch) && - can?(current_user, :push_code, project) + def can_remove_source_branch?(current_user) + !source_project.protected_branch?(source_branch) && + !source_project.root_ref?(source_branch) && + Ability.abilities.allowed?(current_user, :push_code, source_project) end def mr_and_commit_notes diff --git a/app/services/merge_requests/merge_when_build_succeeds_service.rb b/app/services/merge_requests/merge_when_build_succeeds_service.rb index 15dcace5df..2f101e53a3 100644 --- a/app/services/merge_requests/merge_when_build_succeeds_service.rb +++ b/app/services/merge_requests/merge_when_build_succeeds_service.rb @@ -11,13 +11,11 @@ module MergeRequests unless already_approved merge_request.merge_when_build_succeeds = true merge_request.merge_user = @current_user + + SystemNoteService.merge_when_build_succeeds(merge_request, @project, @current_user, merge_request.ci_commit) end merge_request.save - - unless already_approved - SystemNoteService.merge_when_build_succeeds(merge_request, @project, @current_user, merge_request.ci_commit) - end end # Triggers the automatic merge of merge_request once the build succeeds diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 7de4221c4c..ed557fef81 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -132,7 +132,7 @@ class SystemNoteService # Called when 'merge when build succeeds' is executed def self.merge_when_build_succeeds(noteable, project, author, ci_commit) - body = "Approved an automatic merge when the build for #{ci_commit.sha} succeeds" + body = "Enabled an automatic merge when the build for #{ci_commit.sha} succeeds" create_note(noteable: noteable, project: project, author: author, note: body) end diff --git a/app/views/projects/merge_requests/widget/_merged.html.haml b/app/views/projects/merge_requests/widget/_merged.html.haml index a788fcea23..52e34ee617 100644 --- a/app/views/projects/merge_requests/widget/_merged.html.haml +++ b/app/views/projects/merge_requests/widget/_merged.html.haml @@ -13,7 +13,7 @@ %span.label-branch= @merge_request.target_branch The source branch has been removed. - - elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) + - elsif @merge_request.can_remove_source_branch?(current_user) .remove_source_branch_widget %p = succeed '.' do @@ -48,5 +48,3 @@ $('.remove_source_branch_in_progress').hide(); $('.remove_source_branch_widget.failed').show(); }); - - diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index 5ec623b472..279e2ec91f 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -7,13 +7,13 @@ - ci_commit = @merge_request.ci_commit - if ci_commit && ci_commit.active? = f.button class: "btn btn-create btn-grouped merge_when_build_succeeds", name: "merge_when_build_succeeds" do - Merge when Build Succeeds + Merge When Build Succeeds = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do Accept Merge Request Now - else = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do Accept Merge Request - - if @merge_request.can_remove_source_branch? + - if @merge_request.can_remove_source_branch?(current_user) .accept-control.checkbox = label_tag :should_remove_source_branch, class: "remove_source_checkbox" do = check_box_tag :should_remove_source_branch diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml index 51e18f8442..43ba49c5a5 100644 --- a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml +++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml @@ -3,22 +3,25 @@ to be merged automatically when #{link_to "the build", ci_status_path(@merge_request.ci_commit)} succeeds. %div - - if @merge_request.merge_params["should_remove_source_branch"].present? + - source_branch_removed = @merge_request.merge_params["should_remove_source_branch"].present? + - if source_branch_removed = succeed '.' do The changes will be merged into %span.label-branch= @merge_request.target_branch The source branch will be removed. + - else %p = succeed '.' do The changes will be merged into %span.label-branch= @merge_request.target_branch The source branch will not be removed. - .clearfix.prepend-top-10 - - if @merge_request.can_remove_source_branch? && !@merge_request.merge_params["should_remove_source_branch"].present? - = link_to merge_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do - = icon('times') - Remove Source Branch When Merged - - if @merge_request.merge_when_build_succeeds - = link_to cancel_merge_when_build_succeeds_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request), remote: true, method: :post, class: "btn btn-grouped btn-warning btn-sm" do - Cancel Automatic Merge + - if (@merge_request.can_remove_source_branch?(current_user) && !source_branch_removed) || @merge_request.can_cancel_merge_when_build_succeeds?(current_user) + .clearfix.prepend-top-10 + - if @merge_request.can_remove_source_branch?(current_user) && !source_branch_removed + = link_to merge_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do + = icon('times') + Remove Source Branch When Merged + - if @merge_request.can_cancel_merge_when_build_succeeds?(current_user) + = link_to cancel_merge_when_build_succeeds_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request), remote: true, method: :post, class: "btn btn-grouped btn-warning btn-sm" do + Cancel Automatic Merge diff --git a/lib/api/entities.rb b/lib/api/entities.rb index d6aec03d7f..6f9f71b094 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -169,6 +169,7 @@ module API expose :description expose :work_in_progress?, as: :work_in_progress expose :milestone, using: Entities::Milestone + expose :merge_when_build_succeeds end class MergeRequestChanges < MergeRequest diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index b72f816932..32cb1137ef 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -179,11 +179,11 @@ module API # Merge MR # # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - ID of MR - # merge_commit_message (optional) - Custom merge commit message - # should_remove_source_branch - When true, the source branch will be deleted if possible - # merge_when_build_succeeds (optional) - When true, this MR will be merged when the build succeeds + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR + # merge_commit_message (optional) - Custom merge commit message + # should_remove_source_branch (optional) - When true, the source branch will be deleted if possible + # merge_when_build_succeeds (optional) - When true, this MR will be merged when the build succeeds # Example: # PUT /projects/:id/merge_request/:merge_request_id/merge # @@ -193,12 +193,11 @@ module API # Merge request can not be merged # because user dont have permissions to push into target branch unauthorized! unless merge_request.can_be_merged_by?(current_user) - - not_allowed! unless merge_request.open? && !merge_request.work_in_progress? + not_allowed! if !merge_request.open? || merge_request.work_in_progress? merge_request.check_if_can_be_merged if merge_request.unchecked? - render_api_error!('Branch cannot be merged', 406) if merge_request.can_be_merged? + render_api_error!('Branch cannot be merged', 406) unless merge_request.can_be_merged? merge_params = { commit_message: params[:merge_commit_message], @@ -206,7 +205,7 @@ module API } if parse_boolean(params[:merge_when_build_succeeds]) && merge_request.ci_commit && merge_request.ci_commit.active? - ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). + ::MergeRequests::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params). execute(merge_request) else ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params). @@ -224,11 +223,6 @@ module API post ":id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds" do merge_request = user_project.merge_requests.find(params[:merge_request_id]) - allowed = ::Gitlab::GitAccess.new(current_user, user_project). - can_push_to_branch?(merge_request.target_branch) - - # Merge request can not be merged - # because user dont have permissions to push into target branch unauthorized! unless merge_request.can_cancel_merge_when_build_succeeds?(current_user) ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user).cancel(merge_request) diff --git a/spec/factories/ci/commits.rb b/spec/factories/ci/commits.rb index 79e000b7cc..70e3fa319c 100644 --- a/spec/factories/ci/commits.rb +++ b/spec/factories/ci/commits.rb @@ -2,17 +2,18 @@ # # Table name: commits # -# id :integer not null, primary key -# project_id :integer -# ref :string(255) -# sha :string(255) -# before_sha :string(255) -# push_data :text -# created_at :datetime -# updated_at :datetime -# tag :boolean default(FALSE) -# yaml_errors :text -# committed_at :datetime +# id :integer not null, primary key +# project_id :integer +# ref :string(255) +# sha :string(255) +# before_sha :string(255) +# push_data :text +# created_at :datetime +# updated_at :datetime +# tag :boolean default(FALSE) +# yaml_errors :text +# committed_at :datetime +# gl_project_id :integer # # Read about factories at https://github.com/thoughtbot/factory_girl diff --git a/spec/factories/commit_statuses.rb b/spec/factories/commit_statuses.rb index 52de437052..8898b71e2a 100644 --- a/spec/factories/commit_statuses.rb +++ b/spec/factories/commit_statuses.rb @@ -5,7 +5,7 @@ FactoryGirl.define do name 'default' status 'success' description 'commit status' - commit factory: :ci_commit + commit factory: :ci_commit_with_one_job factory :generic_commit_status, class: GenericCommitStatus do name 'generic' diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb new file mode 100644 index 0000000000..b25a3f05e2 --- /dev/null +++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb @@ -0,0 +1,80 @@ +require 'spec_helper' + +feature 'Merge When Build Succeeds', feature: true, js: true do + let(:user) { create(:user) } + + let(:project) { create(:project, :public) } + let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") } + + before do + project.team << [user, :master] + project.enable_ci + end + + context "Active build for Merge Request" do + before do + ci_commit = create(:ci_commit, gl_project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) + ci_build = create(:ci_build, commit: ci_commit) + + login_as user + visit_merge_request(merge_request) + end + + it 'displays the Merge When Build Succeeds button' do + expect(page).to have_button "Merge When Build Succeeds" + end + + context "Merge When Build succeeds enabled" do + before do + click_button "Merge When Build Succeeds" + end + + it 'activates Merge When Build Succeeds feature' do + expect(page).to have_link "Cancel Automatic Merge" + + expect(page).to have_content "Approved by #{user.name} to be merged automatically when the build succeeds." + expect(page).to have_content "The source branch will not be removed." + end + end + end + + context 'When it is enabled' do + # No clue how, but push a new commit to the branch + let(:merge_request) { create(:merge_request_with_diffs, source_project: project, # source_branch: "mepmep", + author: user, title: "Bug NS-04", merge_when_build_succeeds: true) } + + before do + merge_request.source_project.team << [user, :master] + merge_request.source_branch = "feature" + merge_request.target_branch = "master" + merge_request.save! + + ci_commit = create(:ci_commit, gl_project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) + ci_build = create(:ci_build, commit: ci_commit) + + login_as user + visit_merge_request(merge_request) + end + + it 'cancels the automatic merge' do + click_link "Cancel Automatic Merge" + + expect(page).to have_button "Merge When Build Succeeds" + end + + it "allows the user to remove the source branch" do + expect(page).to have_link "Remove Source Branch When Merged" + end + end + + context 'Build is not active' do + it "should not allow for enabling" do + visit_merge_request(merge_request) + expect(page).not_to have_button "Merge When Build Succeeds" + end + end + + def visit_merge_request(merge_request) + visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request) + end +end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 1bd09a1b0f..c7a9765825 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -174,6 +174,30 @@ describe MergeRequest do end end + describe '#can_remove_source_branch' do + let(:user) { build(:user)} + + before do + subject.source_project.team << [user, :master] + end + + it "cant be merged when its a a protected branch" do + subject.source_project.protected_branches = []; + + expect(subject.can_remove_source_branch?(user)).to be_falsey + end + + it "cant remove a root ref" do + subject.source_branch = "master"; + + expect(subject.can_remove_source_branch?(user)).to be_falsey + end + + it "is truthy in all other cases" do + expect(subject.can_remove_source_branch?(user)) + end + end + describe "#reset_merge_when_build_succeeds" do let(:merge_if_green) { create :merge_request, merge_when_build_succeeds: true } it "sets the item to false" do diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index a68c7b1e46..91ae2059e9 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -303,19 +303,21 @@ describe API::API, api: true do end describe "PUT /projects/:id/merge_request/:merge_request_id/merge" do + let (:ci_commit) { create(:ci_commit_without_jobs) } + it "should return merge_request in case of success" do put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user) expect(response.status).to eq(200) end - it "should return 405 if branch can't be merged" do + it "should return 406 if branch can't be merged" do allow_any_instance_of(MergeRequest). to receive(:can_be_merged?).and_return(false) put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user) - expect(response.status).to eq(405) + expect(response.status).to eq(406) expect(json_response['message']).to eq('Branch cannot be merged') end @@ -340,6 +342,17 @@ describe API::API, api: true do expect(response.status).to eq(401) expect(json_response['message']).to eq('401 Unauthorized') end + + it "enables merge when build succeeds if the ci is active" do + allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_return(ci_commit) + allow(ci_commit).to receive(:active?).and_return(true) + + put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user), merge_when_build_succeeds: true + + expect(response.status).to eq(200) + expect(json_response['title']).to eq('Test') + expect(json_response['merge_when_build_succeeds']).to eq(true) + end end describe "PUT /projects/:id/merge_request/:merge_request_id" do diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index 7483f51de0..242524286f 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -13,12 +13,12 @@ describe MergeRequests::MergeService do describe :execute do context 'valid params' do - let(:service) { MergeRequests::MergeService.new(project, user, {}) } + let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') } before do allow(service).to receive(:execute_hooks) - service.execute(merge_request, 'Awesome message') + service.execute(merge_request) end it { expect(merge_request).to be_valid } @@ -37,14 +37,14 @@ describe MergeRequests::MergeService do end context "error handling" do - let(:service) { MergeRequests::MergeService.new(project, user, {}) } + let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') } it 'saves error if there is an exception' do allow(service).to receive(:repository).and_raise("error") allow(service).to receive(:execute_hooks) - service.execute(merge_request, 'Awesome message') + service.execute(merge_request) expect(merge_request.merge_error).to eq("Something went wrong during merge") end diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb new file mode 100644 index 0000000000..8638539173 --- /dev/null +++ b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper' + +describe MergeRequests::MergeWhenBuildSucceedsService do + let(:user) { create(:user) } + let(:merge_request) { create(:merge_request) } + let(:mr_merge_if_green_enabled) { create(:merge_request, merge_when_build_succeeds: true, + source_branch: "source_branch", target_branch: project.default_branch, + source_project: project, target_project: project, state: "opened") } + let(:ci_commit) { create(:ci_commit_with_one_job, ref: mr_merge_if_green_enabled.source_branch) } + let(:project) { create(:project) } + let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, commit_message: 'Awesome message') } + + before do + project.ci_commits = [ci_commit] + project.save! + end + describe "#execute" do + context 'first time enabling' do + before do + allow(merge_request).to receive(:ci_commit).and_return(ci_commit) + end + + it 'sets the params, merge_user, and flag' do + service.execute(merge_request) + + expect(merge_request).to be_valid + expect(merge_request.merge_when_build_succeeds).to be_truthy + expect(merge_request.merge_params).to eq commit_message: 'Awesome message' + expect(merge_request.merge_user).to be user + + note = merge_request.notes.last + expect(note.note).to include 'Enabled an automatic merge when the build for' + end + end + + context 'allready approved' do + let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, new_key: true) } + let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch) } + + before do + allow(mr_merge_if_green_enabled).to receive(:ci_commit).and_return(ci_commit) + allow(mr_merge_if_green_enabled).to receive(:mergeable?).and_return(true) + allow(ci_commit).to receive(:success?).and_return(true) + end + + it 'updates the merge params' do + expect(SystemNoteService).not_to receive(:merge_when_build_succeeds) + + service.execute(mr_merge_if_green_enabled) + expect(mr_merge_if_green_enabled.merge_params).to have_key(:new_key) + end + end + end + + describe "#trigger" do + let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch, status: "success") } + + it "merges all merge requests with merge when build succeeds enabled" do + allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_return(ci_commit) + allow(ci_commit).to receive(:success?).and_return(true) + + expect(MergeWorker).to receive(:perform_async) + service.trigger(build) + end + end + + describe "#cancel" do + before do + service.cancel(mr_merge_if_green_enabled) + end + + it "resets all the merge_when_build_succeeds params" do + expect(mr_merge_if_green_enabled.merge_when_build_succeeds).to be_falsey + expect(mr_merge_if_green_enabled.merge_params).to eq({}) + expect(mr_merge_if_green_enabled.merge_user).to be nil + end + end +end diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 7ee4488521..18b2659c1f 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -17,7 +17,8 @@ describe MergeRequests::RefreshService do source_project: @project, source_branch: 'master', target_branch: 'feature', - target_project: @project) + target_project: @project, + merge_when_build_succeeds: true) @fork_merge_request = create(:merge_request, source_project: @fork_project, @@ -46,6 +47,7 @@ describe MergeRequests::RefreshService do it { expect(@merge_request.notes).not_to be_empty } it { expect(@merge_request).to be_open } + it { expect(@merge_request.merge_when_build_succeeds).to be_falsey} it { expect(@fork_merge_request).to be_open } it { expect(@fork_merge_request.notes).to be_empty } end @@ -146,6 +148,7 @@ describe MergeRequests::RefreshService do end end + def reload_mrs @merge_request.reload @fork_merge_request.reload diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 35912ece64..5d41a5cdc6 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -208,18 +208,28 @@ describe SystemNoteService do end describe '.merge_when_build_succeeds' do - let(:ci_commit) { create :ci_commit, gl_project: project } - let(:merge_request) { create :merge_request, project: project } + let(:ci_commit) { create :ci_commit_without_jobs } + let(:noteable) { create :merge_request } - subject { described_class.merge_when_build_succeeds(merge_request, project, author) } + subject { described_class.merge_when_build_succeeds(noteable, project, author, ci_commit) } it_behaves_like 'a system note' it "posts the Merge When Build Succeeds system note" do - allow(merge_request).to receive(:ci_commit).and_return(ci_commit) - allow(ci_commit).to receive(:short_sha).and_return('12345678') + expect(subject.note).to eq "Enabled an automatic merge when the build for 97de212e80737a608d939f648d959671fb0a0142 succeeds" + end + end - expect(subject.note).to eq "This merge request will be automatically merged when the build for 12345678 succeeds" + describe '.cancel_merge_when_build_succeeds' do + let(:ci_commit) { create :ci_commit_without_jobs } + let(:noteable) { create :merge_request } + + subject { described_class.cancel_merge_when_build_succeeds(noteable, project, author) } + + it_behaves_like 'a system note' + + it "posts the Merge When Build Succeeds system note" do + expect(subject.note).to eq "Canceled the automatic merge" end end From 25907ebe476a24bfdd2c451f18227d4fcf314b07 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Wed, 2 Dec 2015 13:28:21 +0100 Subject: [PATCH 06/42] Doc feature Merge When Build Succeeds --- .../disable_merge_when_build_succeeds.png | Bin 0 -> 20551 bytes .../enable_merge_when_build_succeeds.png | Bin 0 -> 13150 bytes doc/workflow/merge_when_build_succeeds.md | 20 ++++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 doc/workflow/merge_requests/disable_merge_when_build_succeeds.png create mode 100644 doc/workflow/merge_requests/enable_merge_when_build_succeeds.png create mode 100644 doc/workflow/merge_when_build_succeeds.md diff --git a/doc/workflow/merge_requests/disable_merge_when_build_succeeds.png b/doc/workflow/merge_requests/disable_merge_when_build_succeeds.png new file mode 100644 index 0000000000000000000000000000000000000000..a45a4890b6249d6b8ad24408dece3f57873a24ff GIT binary patch literal 20551 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 literal 0 HcmV?d00001 diff --git a/doc/workflow/merge_requests/enable_merge_when_build_succeeds.png b/doc/workflow/merge_requests/enable_merge_when_build_succeeds.png new file mode 100644 index 0000000000000000000000000000000000000000..62a46c9508b582f82c1e8f3cb5c469f7216f5d01 GIT binary patch literal 13150 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 Date: Thu, 3 Dec 2015 10:27:34 +0100 Subject: [PATCH 07/42] Incorporate feedback --- app/models/merge_request.rb | 46 ++++++++++--------- .../merge_when_build_succeeds_service.rb | 9 ++-- app/services/system_note_service.rb | 6 +-- .../merge_requests/_merge_request.html.haml | 5 +- .../merge_requests/widget/_heading.html.haml | 9 ++-- .../widget/open/_accept.html.haml | 3 +- .../open/_merge_when_build_succeeds.html.haml | 24 +++++----- spec/factories/merge_requests.rb | 5 ++ .../merge_when_build_succeeds_spec.rb | 21 +++++++-- spec/models/merge_request_spec.rb | 44 ++++++++++++++---- spec/requests/api/merge_requests_spec.rb | 2 +- .../merge_when_build_succeeds_service_spec.rb | 30 +++++++----- .../merge_requests/refresh_service_spec.rb | 3 +- spec/services/system_note_service_spec.rb | 10 ++-- 14 files changed, 134 insertions(+), 83 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 131dfda6b5..1f81e23c7a 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -2,25 +2,28 @@ # # Table name: merge_requests # -# id :integer not null, primary key -# target_branch :string(255) not null -# source_branch :string(255) not null -# source_project_id :integer not null -# author_id :integer -# assignee_id :integer -# title :string(255) -# created_at :datetime -# updated_at :datetime -# milestone_id :integer -# state :string(255) -# merge_status :string(255) -# target_project_id :integer not null -# iid :integer -# description :text -# position :integer default(0) -# locked_at :datetime -# updated_by_id :integer -# merge_error :string(255) +# id :integer not null, primary key +# target_branch :string(255) not null +# source_branch :string(255) not null +# source_project_id :integer not null +# author_id :integer +# assignee_id :integer +# title :string(255) +# created_at :datetime +# updated_at :datetime +# milestone_id :integer +# state :string(255) +# merge_status :string(255) +# target_project_id :integer not null +# iid :integer +# description :text +# position :integer default(0) +# locked_at :datetime +# updated_by_id :integer +# merge_error :string(255) +# merge_params :text (serialized to hash) +# merge_when_build_succeeds :boolean default(false), not null +# merge_user_id :integer # require Rails.root.join("app/models/commit") @@ -124,6 +127,7 @@ class MergeRequest < ActiveRecord::Base validates :source_branch, presence: true validates :target_project, presence: true validates :target_branch, presence: true + validates :merge_user, presence: true, if: :merge_when_build_succeeds? validate :validate_branches validate :validate_fork @@ -496,8 +500,6 @@ class MergeRequest < ActiveRecord::Base end def ci_commit - if last_commit - source_project.ci_commit(last_commit.id) - end + @ci_commit ||= source_project.ci_commit(last_commit.id) if last_commit end end diff --git a/app/services/merge_requests/merge_when_build_succeeds_service.rb b/app/services/merge_requests/merge_when_build_succeeds_service.rb index 2f101e53a3..5cf7404a49 100644 --- a/app/services/merge_requests/merge_when_build_succeeds_service.rb +++ b/app/services/merge_requests/merge_when_build_succeeds_service.rb @@ -1,6 +1,6 @@ module MergeRequests class MergeWhenBuildSucceedsService < MergeRequests::BaseService - # Marks the passed `merge_request` to be marked when the build succeeds or + # Marks the passed `merge_request` to be merged when the build succeeds or # updates the params for the automatic merge def execute(merge_request) merge_request.merge_params.merge!(params) @@ -12,7 +12,7 @@ module MergeRequests merge_request.merge_when_build_succeeds = true merge_request.merge_user = @current_user - SystemNoteService.merge_when_build_succeeds(merge_request, @project, @current_user, merge_request.ci_commit) + SystemNoteService.merge_when_build_succeeds(merge_request, @project, @current_user, merge_request.last_commit) end merge_request.save @@ -25,8 +25,7 @@ module MergeRequests merge_requests.each do |merge_request| next unless merge_request.merge_when_build_succeeds? - ci_commit = merge_request.ci_commit - if ci_commit && ci_commit.success? && merge_request.mergeable? + if merge_request.ci_commit && merge_request.ci_commit.success? && merge_request.mergeable? MergeWorker.perform_async(merge_request.id, merge_request.merge_user_id, merge_request.merge_params) end end @@ -34,7 +33,7 @@ module MergeRequests # Cancels the automatic merge def cancel(merge_request) - if merge_request.merge_when_build_succeeds? && merge_request.open? && !merge_request.merged? + if merge_request.merge_when_build_succeeds? && merge_request.open? merge_request.reset_merge_when_build_succeeds SystemNoteService.cancel_merge_when_build_succeeds(merge_request, @project, @current_user) diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index ed557fef81..f84e480ca9 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -131,15 +131,15 @@ class SystemNoteService end # Called when 'merge when build succeeds' is executed - def self.merge_when_build_succeeds(noteable, project, author, ci_commit) - body = "Enabled an automatic merge when the build for #{ci_commit.sha} succeeds" + def self.merge_when_build_succeeds(noteable, project, author, last_commit) + body = "Enabled an automatic merge when the build for #{last_commit.to_reference} succeeds" create_note(noteable: noteable, project: project, author: author, note: body) end # Called when 'merge when build succeeds' is canceled def self.cancel_merge_when_build_succeeds(noteable, project, author) - body = "Canceled the automatic merge" + body = "Cancelled the automatic merge" create_note(noteable: noteable, project: project, author: author, note: body) end diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml index c5234c0618..d10ccb3057 100644 --- a/app/views/projects/merge_requests/_merge_request.html.haml +++ b/app/views/projects/merge_requests/_merge_request.html.haml @@ -1,4 +1,3 @@ -- ci_commit = merge_request.ci_commit %li{ class: mr_css_classes(merge_request) } .merge-request-title %span.merge-request-title-text @@ -7,8 +6,8 @@ - merge_request.labels.each do |label| = link_to_label(label, project: merge_request.project) .pull-right.light - - if ci_commit - = render_ci_status(ci_commit) + - if merge_request.ci_commit + = render_ci_status(merge_request.ci_commit) - if merge_request.merged? %span %i.fa.fa-check diff --git a/app/views/projects/merge_requests/widget/_heading.html.haml b/app/views/projects/merge_requests/widget/_heading.html.haml index ba5ad22bca..9513a18f10 100644 --- a/app/views/projects/merge_requests/widget/_heading.html.haml +++ b/app/views/projects/merge_requests/widget/_heading.html.haml @@ -1,13 +1,12 @@ -- ci_commit = @merge_request.ci_commit -- if ci_commit - - status = ci_commit.status +- if @merge_request.ci_commit + - status = @merge_request.ci_commit.status .mr-widget-heading .ci_widget{class: "ci-#{status}"} - = ci_status_icon(ci_commit) + = ci_status_icon(@merge_request.ci_commit) %span CI build #{status} for #{@merge_request.last_commit_short_sha}. %span.ci-coverage - = link_to "View build details", ci_status_path(ci_commit) + = link_to "View build details", ci_status_path(@merge_request.ci_commit) - elsif @merge_request.has_ci? - # Compatibility with old CI integrations (ex jenkins) when you request status from CI server via AJAX diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index 279e2ec91f..f7d872aa45 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -4,8 +4,7 @@ = hidden_field_tag :authenticity_token, form_authenticity_token .accept-merge-holder.clearfix.js-toggle-container .accept-action - - ci_commit = @merge_request.ci_commit - - if ci_commit && ci_commit.active? + - if @merge_request.ci_commit && @merge_request.ci_commit.active? = f.button class: "btn btn-create btn-grouped merge_when_build_succeeds", name: "merge_when_build_succeeds" do Merge When Build Succeeds = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml index 43ba49c5a5..9788d68b54 100644 --- a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml +++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml @@ -1,27 +1,27 @@ %h4 - Approved by #{link_to_member(@project, @merge_request.merge_user, avatar: true)} + Set by #{link_to_member(@project, @merge_request.merge_user, avatar: true)} to be merged automatically when #{link_to "the build", ci_status_path(@merge_request.ci_commit)} succeeds. %div - - source_branch_removed = @merge_request.merge_params["should_remove_source_branch"].present? - - if source_branch_removed + - should_remove_source_branch = @merge_request.merge_params["should_remove_source_branch"].present? + %p = succeed '.' do The changes will be merged into %span.label-branch= @merge_request.target_branch - The source branch will be removed. - - else - %p - = succeed '.' do - The changes will be merged into - %span.label-branch= @merge_request.target_branch + - if should_remove_source_branch + The source branch will be removed. + - else The source branch will not be removed. - - if (@merge_request.can_remove_source_branch?(current_user) && !source_branch_removed) || @merge_request.can_cancel_merge_when_build_succeeds?(current_user) + - remove_source_branch_button = @merge_request.can_remove_source_branch?(current_user) && !should_remove_source_branch + - user_can_cancel_automatic_merge = @merge_request.can_cancel_merge_when_build_succeeds?(current_user) + - if remove_source_branch_button || user_can_cancel_automatic_merge .clearfix.prepend-top-10 - - if @merge_request.can_remove_source_branch?(current_user) && !source_branch_removed + - if remove_source_branch_button = link_to merge_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do = icon('times') Remove Source Branch When Merged - - if @merge_request.can_cancel_merge_when_build_succeeds?(current_user) + + - if user_can_cancel_automatic_merge = link_to cancel_merge_when_build_succeeds_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request), remote: true, method: :post, class: "btn btn-grouped btn-warning btn-sm" do Cancel Automatic Merge diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 729a49c9f7..5b4d7f41bc 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -65,6 +65,11 @@ FactoryGirl.define do target_branch "master" end + trait :merge_when_build_succeeds do + merge_when_build_succeeds true + merge_user author + end + factory :closed_merge_request, traits: [:closed] factory :reopened_merge_request, traits: [:reopened] factory :merge_request_with_diffs, traits: [:with_diffs] diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb index b25a3f05e2..2e64e903d1 100644 --- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb @@ -1,4 +1,6 @@ require 'spec_helper' +# rubocop:disable Lint/UselessAssignment +# As rubocop doesn't see a need for both `ci_commit` and `ci_build` feature 'Merge When Build Succeeds', feature: true, js: true do let(:user) { create(:user) } @@ -32,16 +34,20 @@ feature 'Merge When Build Succeeds', feature: true, js: true do it 'activates Merge When Build Succeeds feature' do expect(page).to have_link "Cancel Automatic Merge" - expect(page).to have_content "Approved by #{user.name} to be merged automatically when the build succeeds." + expect(page).to have_content "Set by #{user.name} to be merged automatically when the build succeeds." expect(page).to have_content "The source branch will not be removed." + + visit_merge_request(merge_request) # Needed to refresh the page + expect(page).to have_content /Enabled an automatic merge when the build for [0-9a-f]{8} succeeds/i end end end context 'When it is enabled' do - # No clue how, but push a new commit to the branch - let(:merge_request) { create(:merge_request_with_diffs, source_project: project, # source_branch: "mepmep", - author: user, title: "Bug NS-04", merge_when_build_succeeds: true) } + let(:merge_request) do + create(:merge_request_with_diffs, source_project: project, author: user, + merge_user: user, title: "MepMep", merge_when_build_succeeds: true) + end before do merge_request.source_project.team << [user, :master] @@ -60,10 +66,16 @@ feature 'Merge When Build Succeeds', feature: true, js: true do click_link "Cancel Automatic Merge" expect(page).to have_button "Merge When Build Succeeds" + + visit_merge_request(merge_request) # Needed to refresh the page + expect(page).to have_content "Cancelled the automatic merge" end it "allows the user to remove the source branch" do expect(page).to have_link "Remove Source Branch When Merged" + + click_link "Remove Source Branch When Merged" + expect(page).to have_content "The source branch will be removed" end end @@ -78,3 +90,4 @@ feature 'Merge When Build Succeeds', feature: true, js: true do visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request) end end +# rubocop:enable Lint/UselessAssignment diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index c7a9765825..63e1cd1fb9 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -48,6 +48,24 @@ describe MergeRequest do describe 'validation' do it { is_expected.to validate_presence_of(:target_branch) } it { is_expected.to validate_presence_of(:source_branch) } + + context "Validation of merge user with Merge When Build succeeds" do + it "allows user to be nil when the feature is disabled" do + expect(subject).to be_valid + end + + it "is invalid without merge user" do + subject.merge_when_build_succeeds = true + expect(subject).not_to be_valid + end + + it "is valid with merge user" do + subject.merge_when_build_succeeds = true + subject.merge_user = build(:user) + + expect(subject).to be_valid + end + end end describe 'respond to' do @@ -175,31 +193,41 @@ describe MergeRequest do end describe '#can_remove_source_branch' do - let(:user) { build(:user)} + let(:user) { create(:user) } + let(:user2) { create(:user) } before do subject.source_project.team << [user, :master] + + subject.source_branch = "feature" + subject.target_branch = "master" + subject.save! end - it "cant be merged when its a a protected branch" do - subject.source_project.protected_branches = []; - + it "can't be removed when its a protected branch" do + allow(subject.source_project).to receive(:protected_branch?).and_return(true) expect(subject.can_remove_source_branch?(user)).to be_falsey end it "cant remove a root ref" do - subject.source_branch = "master"; + subject.source_branch = "master" + subject.target_branch = "feature" expect(subject.can_remove_source_branch?(user)).to be_falsey end - it "is truthy in all other cases" do - expect(subject.can_remove_source_branch?(user)) + it "is unable to remove the source branch for a project the user cannot push to" do + expect(subject.can_remove_source_branch?(user2)).to be_falsey + end + + it "is can be removed in all other cases" do + expect(subject.can_remove_source_branch?(user)).to be_truthy end end describe "#reset_merge_when_build_succeeds" do - let(:merge_if_green) { create :merge_request, merge_when_build_succeeds: true } + let(:merge_if_green) { create :merge_request, merge_when_build_succeeds: true, merge_user: create(:user) } + it "sets the item to false" do merge_if_green.reset_merge_when_build_succeeds merge_if_green.reload diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 91ae2059e9..6b7a066ac4 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -303,7 +303,7 @@ describe API::API, api: true do end describe "PUT /projects/:id/merge_request/:merge_request_id/merge" do - let (:ci_commit) { create(:ci_commit_without_jobs) } + let(:ci_commit) { create(:ci_commit_without_jobs) } it "should return merge_request in case of success" do put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user) diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb index 8638539173..a62d88cde8 100644 --- a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb +++ b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb @@ -3,37 +3,38 @@ require 'spec_helper' describe MergeRequests::MergeWhenBuildSucceedsService do let(:user) { create(:user) } let(:merge_request) { create(:merge_request) } - let(:mr_merge_if_green_enabled) { create(:merge_request, merge_when_build_succeeds: true, - source_branch: "source_branch", target_branch: project.default_branch, - source_project: project, target_project: project, state: "opened") } - let(:ci_commit) { create(:ci_commit_with_one_job, ref: mr_merge_if_green_enabled.source_branch) } + + let(:mr_merge_if_green_enabled) do + create(:merge_request, merge_when_build_succeeds: true, merge_user: user, + source_branch: "source_branch", target_branch: project.default_branch, + source_project: project, target_project: project, state: "opened") + end + let(:project) { create(:project) } + let(:ci_commit) { create(:ci_commit_with_one_job, ref: mr_merge_if_green_enabled.source_branch, gl_project: project) } let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, commit_message: 'Awesome message') } - before do - project.ci_commits = [ci_commit] - project.save! - end describe "#execute" do context 'first time enabling' do before do allow(merge_request).to receive(:ci_commit).and_return(ci_commit) + service.execute(merge_request) end it 'sets the params, merge_user, and flag' do - service.execute(merge_request) - expect(merge_request).to be_valid expect(merge_request.merge_when_build_succeeds).to be_truthy expect(merge_request.merge_params).to eq commit_message: 'Awesome message' expect(merge_request.merge_user).to be user + end + it 'creates a system note' do note = merge_request.notes.last - expect(note.note).to include 'Enabled an automatic merge when the build for' + expect(note.note).to match /Enabled an automatic merge when the build for (\w+\/\w+@)?[0-9a-z]{8}/ end end - context 'allready approved' do + context 'already approved' do let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, new_key: true) } let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch) } @@ -74,5 +75,10 @@ describe MergeRequests::MergeWhenBuildSucceedsService do expect(mr_merge_if_green_enabled.merge_params).to eq({}) expect(mr_merge_if_green_enabled.merge_user).to be nil end + + it 'Posts a system note' do + note = mr_merge_if_green_enabled.notes.last + expect(note.note).to include 'Cancelled the automatic merge' + end end end diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 18b2659c1f..9a8174f95f 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -18,7 +18,8 @@ describe MergeRequests::RefreshService do source_branch: 'master', target_branch: 'feature', target_project: @project, - merge_when_build_succeeds: true) + merge_when_build_succeeds: true, + merge_user: @user) @fork_merge_request = create(:merge_request, source_project: @fork_project, diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 5d41a5cdc6..333035f2d2 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -208,20 +208,20 @@ describe SystemNoteService do end describe '.merge_when_build_succeeds' do - let(:ci_commit) { create :ci_commit_without_jobs } + let(:ci_commit) { build :ci_commit_without_jobs } let(:noteable) { create :merge_request } - subject { described_class.merge_when_build_succeeds(noteable, project, author, ci_commit) } + subject { described_class.merge_when_build_succeeds(noteable, project, author, noteable.last_commit) } it_behaves_like 'a system note' it "posts the Merge When Build Succeeds system note" do - expect(subject.note).to eq "Enabled an automatic merge when the build for 97de212e80737a608d939f648d959671fb0a0142 succeeds" + expect(subject.note).to match /Enabled an automatic merge when the build for (\w+\/\w+@)?[0-9a-f]{40} succeeds/ end end describe '.cancel_merge_when_build_succeeds' do - let(:ci_commit) { create :ci_commit_without_jobs } + let(:ci_commit) { build :ci_commit_without_jobs } let(:noteable) { create :merge_request } subject { described_class.cancel_merge_when_build_succeeds(noteable, project, author) } @@ -229,7 +229,7 @@ describe SystemNoteService do it_behaves_like 'a system note' it "posts the Merge When Build Succeeds system note" do - expect(subject.note).to eq "Canceled the automatic merge" + expect(subject.note).to eq "Cancelled the automatic merge" end end From 46278ec7ba7c618acaf7381ad466742ce84e33db Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 7 Dec 2015 09:59:04 +0100 Subject: [PATCH 08/42] Button fix --- app/services/system_note_service.rb | 2 +- .../widget/open/_accept.html.haml | 33 ++++++++++++++++--- .../merge_when_build_succeeds_spec.rb | 2 +- spec/models/merge_request_spec.rb | 2 +- .../merge_when_build_succeeds_service_spec.rb | 2 +- spec/services/system_note_service_spec.rb | 2 +- 6 files changed, 34 insertions(+), 9 deletions(-) diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index f84e480ca9..6d15a49145 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -139,7 +139,7 @@ class SystemNoteService # Called when 'merge when build succeeds' is canceled def self.cancel_merge_when_build_succeeds(noteable, project, author) - body = "Cancelled the automatic merge" + body = "Canceled the automatic merge" create_note(noteable: noteable, project: project, author: author, note: body) end diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index f7d872aa45..c2badf342d 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -5,10 +5,22 @@ .accept-merge-holder.clearfix.js-toggle-container .accept-action - if @merge_request.ci_commit && @merge_request.ci_commit.active? - = f.button class: "btn btn-create btn-grouped merge_when_build_succeeds", name: "merge_when_build_succeeds" do - Merge When Build Succeeds - = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do - Accept Merge Request Now + %span.btn-group + = link_to "#", class: "btn btn-create merge_when_build_succeeds" do + Merge When Build Succeeds + %a.btn.btn-success.dropdown-toggle{ 'data-toggle' => 'dropdown' } + %span.caret + %span.sr-only + Select Merge Moment + %ul.dropdown-menu.dropdown-menu-right{ role: 'menu' } + %li + = link_to "#", class: "merge_when_build_succeeds" do + = icon('check fw') + Merge When Build Succeeds + %li + = link_to "#", class: "accept_merge_request" do + = icon('warning fw') + Accept Merge Request Now - else = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do Accept Merge Request @@ -26,6 +38,8 @@ text: @merge_request.merge_commit_message, rows: 14, hint: true + = hidden_field_tag :merge_when_build_succeeds, "" + :javascript $('.accept_merge_request').on('click', function() { $(this).html(" Merge in progress"); @@ -34,3 +48,14 @@ $('.accept-mr-form').on('ajax:send', function() { $(".accept-mr-form :input").disable(); }); + + $('a.accept_merge_request').on('click', function(e) { + e.preventDefault(); + $(this).closest("form").submit(); + }); + + $('a.merge_when_build_succeeds').on('click', function(e) { + e.preventDefault(); + $("#merge_when_build_succeeds").val("1"); + $(this).closest("form").submit(); + }); diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb index 2e64e903d1..b5f319f204 100644 --- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb @@ -68,7 +68,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do expect(page).to have_button "Merge When Build Succeeds" visit_merge_request(merge_request) # Needed to refresh the page - expect(page).to have_content "Cancelled the automatic merge" + expect(page).to have_content "Canceled the automatic merge" end it "allows the user to remove the source branch" do diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 63e1cd1fb9..33acfa37fe 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -192,7 +192,7 @@ describe MergeRequest do end end - describe '#can_remove_source_branch' do + describe '#can_remove_source_branch?' do let(:user) { create(:user) } let(:user2) { create(:user) } diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb index a62d88cde8..188fda6211 100644 --- a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb +++ b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb @@ -78,7 +78,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do it 'Posts a system note' do note = mr_merge_if_green_enabled.notes.last - expect(note.note).to include 'Cancelled the automatic merge' + expect(note.note).to include 'Canceled the automatic merge' end end end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 333035f2d2..15173cee0a 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -229,7 +229,7 @@ describe SystemNoteService do it_behaves_like 'a system note' it "posts the Merge When Build Succeeds system note" do - expect(subject.note).to eq "Cancelled the automatic merge" + expect(subject.note).to eq "Canceled the automatic merge" end end From cfc95b828724b0d7cb07254091e675d6d8093dba Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 7 Dec 2015 10:14:37 +0100 Subject: [PATCH 09/42] Fix schema --- db/schema.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index fb59e18762..94b87040d8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -476,9 +476,9 @@ ActiveRecord::Schema.define(version: 20151203162133) do add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", unique: true, using: :btree create_table "merge_requests", force: :cascade do |t| - t.string "target_branch", null: false - t.string "source_branch", null: false - t.integer "source_project_id", null: false + t.string "target_branch", null: false + t.string "source_branch", null: false + t.integer "source_project_id", null: false t.integer "author_id" t.integer "assignee_id" t.string "title" @@ -487,13 +487,16 @@ ActiveRecord::Schema.define(version: 20151203162133) do t.integer "milestone_id" t.string "state" t.string "merge_status" - t.integer "target_project_id", null: false + t.integer "target_project_id", null: false t.integer "iid" t.text "description" - t.integer "position", default: 0 + t.integer "position", default: 0 t.datetime "locked_at" t.integer "updated_by_id" t.string "merge_error" + t.text "merge_params" + t.boolean "merge_when_build_succeeds", default: false, null: false + t.integer "merge_user_id" end add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree From 6eb75ed6ad2710126b577f8093e78faff64bae1b Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 7 Dec 2015 11:29:23 +0100 Subject: [PATCH 10/42] Fix specs --- .../merge_requests/merge_when_build_succeeds_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb index b5f319f204..3a8f0a344e 100644 --- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb @@ -23,12 +23,12 @@ feature 'Merge When Build Succeeds', feature: true, js: true do end it 'displays the Merge When Build Succeeds button' do - expect(page).to have_button "Merge When Build Succeeds" + expect(page).to have_link "Merge When Build Succeeds" end context "Merge When Build succeeds enabled" do before do - click_button "Merge When Build Succeeds" + click_link "Merge When Build Succeeds" end it 'activates Merge When Build Succeeds feature' do @@ -65,7 +65,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do it 'cancels the automatic merge' do click_link "Cancel Automatic Merge" - expect(page).to have_button "Merge When Build Succeeds" + expect(page).to have_link "Merge When Build Succeeds" visit_merge_request(merge_request) # Needed to refresh the page expect(page).to have_content "Canceled the automatic merge" @@ -82,7 +82,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do context 'Build is not active' do it "should not allow for enabling" do visit_merge_request(merge_request) - expect(page).not_to have_button "Merge When Build Succeeds" + expect(page).not_to have_link "Merge When Build Succeeds" end end From 96520227ae6fc5b02b0725bc515511960bcfefed Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 7 Dec 2015 11:29:48 +0100 Subject: [PATCH 11/42] Prevent Firefox from remembering hidden field value --- app/views/projects/merge_requests/widget/open/_accept.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index c2badf342d..0fe3af97b7 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -38,7 +38,7 @@ text: @merge_request.merge_commit_message, rows: 14, hint: true - = hidden_field_tag :merge_when_build_succeeds, "" + = hidden_field_tag :merge_when_build_succeeds, "", autocomplete: "off" :javascript $('.accept_merge_request').on('click', function() { From 4c8666e69fc64200bdd2f5069bbc8c9b22fe12ab Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 7 Dec 2015 11:30:09 +0100 Subject: [PATCH 12/42] Fix commit message textarea position --- .../widget/open/_accept.html.haml | 63 ++++++++++--------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index 0fe3af97b7..6b4395fe4d 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -3,37 +3,38 @@ = form_for [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f| = hidden_field_tag :authenticity_token, form_authenticity_token .accept-merge-holder.clearfix.js-toggle-container - .accept-action - - if @merge_request.ci_commit && @merge_request.ci_commit.active? - %span.btn-group - = link_to "#", class: "btn btn-create merge_when_build_succeeds" do - Merge When Build Succeeds - %a.btn.btn-success.dropdown-toggle{ 'data-toggle' => 'dropdown' } - %span.caret - %span.sr-only - Select Merge Moment - %ul.dropdown-menu.dropdown-menu-right{ role: 'menu' } - %li - = link_to "#", class: "merge_when_build_succeeds" do - = icon('check fw') - Merge When Build Succeeds - %li - = link_to "#", class: "accept_merge_request" do - = icon('warning fw') - Accept Merge Request Now - - else - = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do - Accept Merge Request - - if @merge_request.can_remove_source_branch?(current_user) - .accept-control.checkbox - = label_tag :should_remove_source_branch, class: "remove_source_checkbox" do - = check_box_tag :should_remove_source_branch - Remove source branch - .accept-control.right - = link_to "#", class: "modify-merge-commit-link js-toggle-button" do - = icon('edit') - Modify commit message - .js-toggle-content.hide.prepend-top-20 + .clearfix + .accept-action + - if @merge_request.ci_commit && @merge_request.ci_commit.active? + %span.btn-group + = link_to "#", class: "btn btn-create merge_when_build_succeeds" do + Merge When Build Succeeds + %a.btn.btn-success.dropdown-toggle{ 'data-toggle' => 'dropdown' } + %span.caret + %span.sr-only + Select Merge Moment + %ul.dropdown-menu.dropdown-menu-right{ role: 'menu' } + %li + = link_to "#", class: "merge_when_build_succeeds" do + = icon('check fw') + Merge When Build Succeeds + %li + = link_to "#", class: "accept_merge_request" do + = icon('warning fw') + Merge Immediately + - else + = f.button class: "btn btn-create btn-grouped accept_merge_request #{status_class}" do + Accept Merge Request + - if @merge_request.can_remove_source_branch?(current_user) + .accept-control.checkbox + = label_tag :should_remove_source_branch, class: "remove_source_checkbox" do + = check_box_tag :should_remove_source_branch + Remove source branch + .accept-control.right + = link_to "#", class: "modify-merge-commit-link js-toggle-button" do + = icon('edit') + Modify commit message + .js-toggle-content.hide.prepend-top-default = render 'shared/commit_message_container', params: params, text: @merge_request.merge_commit_message, rows: 14, hint: true From e7969d6f6c743ead94b3b430b9184ad21f647337 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 7 Dec 2015 11:54:07 +0100 Subject: [PATCH 13/42] Satisfy Douwe Maan --- CHANGELOG | 2 +- app/services/system_note_service.rb | 2 +- .../merge_when_build_succeeds_spec.rb | 14 ++++++-------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6c2fa75899..163a0ea54e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.3.0 (unreleased) -- Merge when build succeeds (Zeger-Jan van de Weg) + - Merge when build succeeds (Zeger-Jan van de Weg) - Fix: Assignee selector is empty when 'Unassigned' is selected (Jose Corcuera) - Fix 500 error when update group member permission - Trim leading and trailing whitespace of milestone and issueable titles (Jose Corcuera) diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 7cb9417b13..6975b2ee55 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -132,7 +132,7 @@ class SystemNoteService # Called when 'merge when build succeeds' is executed def self.merge_when_build_succeeds(noteable, project, author, last_commit) - body = "Enabled an automatic merge when the build for #{last_commit.to_reference} succeeds" + body = "Enabled an automatic merge when the build for #{last_commit.to_reference(project)} succeeds" create_note(noteable: noteable, project: project, author: author, note: body) end diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb index 3a8f0a344e..ee2fb25e9e 100644 --- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb @@ -1,6 +1,4 @@ require 'spec_helper' -# rubocop:disable Lint/UselessAssignment -# As rubocop doesn't see a need for both `ci_commit` and `ci_build` feature 'Merge When Build Succeeds', feature: true, js: true do let(:user) { create(:user) } @@ -14,10 +12,10 @@ feature 'Merge When Build Succeeds', feature: true, js: true do end context "Active build for Merge Request" do - before do - ci_commit = create(:ci_commit, gl_project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) - ci_build = create(:ci_build, commit: ci_commit) + let!(:ci_commit) { create(:ci_commit, gl_project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) } + let!(:ci_build) { create(:ci_build, commit: ci_commit) } + before do login_as user visit_merge_request(merge_request) end @@ -49,14 +47,15 @@ feature 'Merge When Build Succeeds', feature: true, js: true do merge_user: user, title: "MepMep", merge_when_build_succeeds: true) end + let!(:ci_commit) { create(:ci_commit, gl_project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) } + let!(:ci_build) { create(:ci_build, commit: ci_commit) } + before do merge_request.source_project.team << [user, :master] merge_request.source_branch = "feature" merge_request.target_branch = "master" merge_request.save! - ci_commit = create(:ci_commit, gl_project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) - ci_build = create(:ci_build, commit: ci_commit) login_as user visit_merge_request(merge_request) @@ -90,4 +89,3 @@ feature 'Merge When Build Succeeds', feature: true, js: true do visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request) end end -# rubocop:enable Lint/UselessAssignment From b2b548de9d74b01816baca822d39f9dd543bbbf7 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 8 Dec 2015 14:02:34 +0100 Subject: [PATCH 14/42] Rewrite docs --- doc/workflow/README.md | 1 + .../disable_merge_when_build_succeeds.png | Bin 20551 -> 0 bytes .../enable_merge_when_build_succeeds.png | Bin 13150 -> 0 bytes doc/workflow/merge_when_build_succeeds.md | 19 +++++++----------- .../merge_when_build_succeeds/enable.png | Bin 0 -> 151112 bytes .../merge_when_build_succeeds/status.png | Bin 0 -> 180318 bytes 6 files changed, 8 insertions(+), 12 deletions(-) delete mode 100644 doc/workflow/merge_requests/disable_merge_when_build_succeeds.png delete mode 100644 doc/workflow/merge_requests/enable_merge_when_build_succeeds.png create mode 100644 doc/workflow/merge_when_build_succeeds/enable.png create mode 100644 doc/workflow/merge_when_build_succeeds/status.png diff --git a/doc/workflow/README.md b/doc/workflow/README.md index a6b4d95118..d2642495c9 100644 --- a/doc/workflow/README.md +++ b/doc/workflow/README.md @@ -17,4 +17,5 @@ - [Milestones](milestones.md) - [Merge Requests](merge_requests.md) - ["Work In Progress" Merge Requests](wip_merge_requests.md) +- [Merge When Build Succeeds](merge_when_build_succeeds.md) - [Manage large binaries with Git LFS](lfs/manage_large_binaries_with_git_lfs.md) diff --git a/doc/workflow/merge_requests/disable_merge_when_build_succeeds.png b/doc/workflow/merge_requests/disable_merge_when_build_succeeds.png deleted file mode 100644 index a45a4890b6249d6b8ad24408dece3f57873a24ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20551 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 diff --git a/doc/workflow/merge_requests/enable_merge_when_build_succeeds.png b/doc/workflow/merge_requests/enable_merge_when_build_succeeds.png deleted file mode 100644 index 62a46c9508b582f82c1e8f3cb5c469f7216f5d01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13150 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 literal 0 HcmV?d00001 diff --git a/doc/workflow/merge_when_build_succeeds/status.png b/doc/workflow/merge_when_build_succeeds/status.png new file mode 100644 index 0000000000000000000000000000000000000000..c856c7d14dc6ba2f0c89f3e6d7c0e3de39e0dcfe GIT binary patch literal 180318 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

M$^a^8jm41-_{C#PI0dj6faq1`ClUL&ToH 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 DsM0JO literal 0 HcmV?d00001 From d00d3444a45f81a5e79a1161acb44fca2df3c1c7 Mon Sep 17 00:00:00 2001 From: Kelvin Date: Tue, 8 Dec 2015 18:23:30 +0300 Subject: [PATCH 15/42] Remove the prepended v on GitLab Workhorse upgrade doc --- doc/update/patch_versions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md index 957354decb..c19ee49f9e 100644 --- a/doc/update/patch_versions.md +++ b/doc/update/patch_versions.md @@ -47,7 +47,7 @@ sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION` -b v`ca ```bash cd /home/git/gitlab-workhorse sudo -u git -H git fetch -sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` -b v`cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` +sudo -u git -H git checkout `cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` -b `cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` ``` ### 5. Install libs, migrations, etc. From 4f074aaa14faa8a866f18a80f58b66cd023a141f Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 25 Nov 2015 14:41:14 +0100 Subject: [PATCH 16/42] Introduce CI documentation for services and languages --- doc/README.md | 12 ++ doc/ci/README.md | 12 ++ doc/ci/docker/using_docker_images.md | 115 +++++++---------- doc/ci/languages/README.md | 3 + doc/ci/languages/php.md | 178 +++++++++++++++++++++++++++ doc/ci/services/README.md | 6 + doc/ci/services/docker-services.md | 5 + doc/ci/services/mysql.md | 72 +++++++++++ doc/ci/services/postgres.md | 70 +++++++++++ doc/ci/services/redis.md | 40 ++++++ doc/ci/ssh_keys/README.md | 114 +++++++++++++++++ 11 files changed, 559 insertions(+), 68 deletions(-) create mode 100644 doc/ci/languages/README.md create mode 100644 doc/ci/languages/php.md create mode 100644 doc/ci/services/README.md create mode 100644 doc/ci/services/docker-services.md create mode 100644 doc/ci/services/mysql.md create mode 100644 doc/ci/services/postgres.md create mode 100644 doc/ci/services/redis.md create mode 100644 doc/ci/ssh_keys/README.md diff --git a/doc/README.md b/doc/README.md index 58ab5dd08e..a7025f7af1 100644 --- a/doc/README.md +++ b/doc/README.md @@ -24,9 +24,21 @@ - [Using Docker Images](ci/docker/using_docker_images.md) - [Using Docker Build](ci/docker/using_docker_build.md) - [Using Variables](ci/variables/README.md) +- [Using SSH keys](ci/ssh_keys/README.md) - [User permissions](ci/permissions/README.md) - [API](ci/api/README.md) +### CI Languages + ++ [Testing PHP](ci/languages/php.md) + +## CI Services + ++ [Using MySQL](ci/services/mysql.md) ++ [Using PostgreSQL](ci/services/postgres.md) ++ [Using Redis](ci/services/redis.md) ++ [Using Other Services](ci/docker/using_docker_images.html#how-to-use-other-images-as-services) + ### CI Examples - [Test and deploy Ruby applications to Heroku](ci/examples/test-and-deploy-ruby-application-to-heroku.md) diff --git a/doc/ci/README.md b/doc/ci/README.md index 97325069ce..ae921b6f98 100644 --- a/doc/ci/README.md +++ b/doc/ci/README.md @@ -9,6 +9,18 @@ + [Using Docker Images](docker/using_docker_images.md) + [Using Docker Build](docker/using_docker_build.md) + [Using Variables](variables/README.md) ++ [Using SSH keys](ssh_keys/README.md) + +### Languages + ++ [Testing PHP](languages/php.md) + +### Services + ++ [Using MySQL](services/mysql.md) ++ [Using PostgreSQL](services/postgres.md) ++ [Using Redis](services/redis.md) ++ [Using Other Services](docker/using_docker_images.html#how-to-use-other-images-as-services) ### Examples diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index 1feae62b1c..2f0ca19cd0 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -42,7 +42,44 @@ So, **to access your database service you have to connect to host: `mysql` inste ### How to use other images as services? You are not limited to have only database services. -You can hand modify `config.toml` to add any image as service found at [Docker Hub](https://registry.hub.docker.com/). +You can add the services to `.gitlab-ci.yml` or hand modify the `config.toml`. +You can use any image as service found at [Docker Hub](https://registry.hub.docker.com/). + +### Define image and services from `.gitlab-ci.yml` +You can simply define image or list services that you want to use for the build time. +``` +image: ruby:2.2 +services: + - postgres:9.3 +before_install: + - bundle install + +test: + script: + - bundle exec rake spec +``` + +It's possible to define image and service per-job: +``` +before_install: + - bundle install + +test:2.1: + image: ruby:2.1 + services: + - postgres:9.3 + script: + - bundle exec rake spec + +test:2.2: + image: ruby:2.2 + services: + - postgres:9.4 + script: + - bundle exec rake spec +``` + +### Define image and services in `config.toml` Look for `[runners.docker]` section: ``` [runners.docker] @@ -50,13 +87,16 @@ Look for `[runners.docker]` section: services = ["mysql:latest", "postgres:latest"] ``` +The image and services defined these way will be added to all builds run by that runner. + +### Accessing the services For example you need `wordpress` instance to test some API integration with `Wordpress`. -You can for example use this image: [tutum/wordpress](https://registry.hub.docker.com/u/tutum/wordpress/). -This is image that have fully preconfigured `wordpress` and have `MySQL` server built-in: +You can for example use this image: [tutum/wordpress](https://registry.hub.docker.com/u/tutum/wordpress/). + ``` -[runners.docker] - image = "ruby:2.1" - services = ["mysql:latest", "postgres:latest", "tutum/wordpress:latest"] +# .gitlab-ci.yml +services: +- tutum/wordpress:latest ``` Next time when you run your application the `tutum/wordpress` will be started @@ -64,7 +104,7 @@ and you will have access to it from your build container under hostname: `tutum_ Alias hostname for the service is made from the image name: 1. Everything after `:` is stripped, -2. '/' is replaced with `__`. +2. '/' is replaced to `__`. ### Configuring services Many services accept environment variables, which allow you to easily change database names or set account names depending on the environment. @@ -99,67 +139,6 @@ or README page for any other Docker image. **Note: All variables will passed to all service containers. It's not designed to distinguish which variable should go where.** -### Overwrite image and services -It's possible to overwrite `docker-image` and specify services from `.gitlab-ci.yml`. -If you add to your YAML the `image` and the `services` these parameters -be used instead of the ones that were specified during runner's registration. -``` -image: ruby:2.2 -services: - - postgres:9.3 -before_install: - - bundle install - -test: - script: - - bundle exec rake spec -``` - -It's possible to define image and service per-job: -``` -before_install: - - bundle install - -test:2.1: - image: ruby:2.1 - services: - - postgres:9.3 - script: - - bundle exec rake spec - -test:2.2: - image: ruby:2.2 - services: - - postgres:9.4 - script: - - bundle exec rake spec -``` - -#### How to enable overwriting? -To enable overwriting you have to **enable it first** (it's disabled by default for security reasons). -You can do that by hand modifying runner configuration: `config.toml`. -Please go to section where is `[runners.docker]` definition for your runner. -Add `allowed_images` and `allowed_services` to specify what images are allowed to be picked from `.gitlab-ci.yml`: -``` -[runners.docker] - image = "ruby:2.1" - allowed_images = ["ruby:*", "python:*"] - allowed_services = ["mysql:*", "redis:*"] -``` -This enables you to use in your `.gitlab-ci.yml` any image that matches above wildcards. -You will be able to pick only `ruby` and `python` images. -The same rule can be applied to limit services. - -If you are courageous enough, you can make it fully open and accept everything: -``` -[runners.docker] - image = "ruby:2.1" - allowed_images = ["*", "*/*"] - allowed_services = ["*", "*/*"] -``` - -**It the feature is not enabled, or image isn't allowed the error message will be put into the build log.** - ### How Docker integration works 1. Create any service container: `mysql`, `postgresql`, `mongodb`, `redis`. 1. Create cache container to store all volumes as defined in `config.toml` and `Dockerfile` of build image (`ruby:2.1` as in above example). diff --git a/doc/ci/languages/README.md b/doc/ci/languages/README.md new file mode 100644 index 0000000000..375adf58d1 --- /dev/null +++ b/doc/ci/languages/README.md @@ -0,0 +1,3 @@ +### Languages + ++ [Testing PHP](php.md) diff --git a/doc/ci/languages/php.md b/doc/ci/languages/php.md new file mode 100644 index 0000000000..e058918200 --- /dev/null +++ b/doc/ci/languages/php.md @@ -0,0 +1,178 @@ +## Testing PHP projects + +This guide covers basic of building PHP projects. + +Is it possible to test PHP apps on any system. +However, it will require manual configuration. +The simplest is to use Docker executor as described below. + +### PHP projects on Docker executor +It's possible to official [PHP](https://hub.docker.com/_/php/) repositories on Docker Hub. +They allow to test PHP projects against different versions of the runtime. +However, they require additional configuration. + +To build PHP project you need to create valid `.gitlab-ci.yml` describing the build environment: +1. First you need to specify PHP image as described here: http://doc.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-image. To your `.gitlab-ci.yml` add: + + image: php:5.6 + +2. The official images are great, but they are lacking a few useful tools for testing. We need to install them first in build environment. Create `ci/docker_install.sh` file with following content: + + #!/bin/bash + + # We need to install dependencies only for Docker + [[ ! -e /.dockerinit ]] && exit 0 + + set -xe + + # Install git (the php image doesn't have it) which is required by composer + apt-get update -yqq + apt-get install git -yqq + + # Install phpunit, the tool that we will use for testing + curl -o /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar + chmod +x /usr/local/bin/phpunit + + # Install mysql driver + # Here you can install any other extension that you need + docker-php-ext-install pdo_mysql + +3. From your `.gitlab-ci.yml` run the created script: + + before_script: + - bash ci/docker_install.sh > /dev/null + +4. Now you can run your tests. Usually it will be `phpunit` with arguments: + + test:app: + script: + - phpunit --configuration phpunit_myapp.xml --coverage-text + +5. Commit your files, and push them to GitLab to see if it works. With GitLab Runner 1.0 you can also test the changes locally. From your terminal execute: + + # Check using docker executor + gitlab-runner exec docker test:app + + # Check using shell executor + gitlab-runner exec shell test:app + +The final `.gitlab-ci.yml` should look similar to this: + + # Select image from https://hub.docker.com/_/php/ + image: php:5.6 + + before_script: + # Install dependencies + - ci/docker_install.sh > /dev/null + + test:app: + script: + - phpunit --configuration phpunit_myapp.xml --coverage-text + +#### Test against different PHP versions in Docker builds + +You can also test against multiple version of PHP runtime: + + before_script: + # Install dependencies + - ci/docker_install.sh > /dev/null + + # We test PHP5.6 + test:5.6: + image: php:5.6 + script: + - phpunit --configuration phpunit_myapp.xml --coverage-text + + # We test PHP7.0 + test:7.0: + image: php:7.0 + script: + - phpunit --configuration phpunit_myapp.xml --coverage-text + +#### Custom PHP configuration in Docker builds + +You can customise your PHP environment by putting your .ini file into `/usr/local/etc/php/conf.d/`: + + before_script: + - cp my_php.ini /usr/local/etc/php/conf.d/test.ini + +### Test PHP projects using Shell + +Shell executor runs your builds in terminal session of your server. Thus in order to test your projects you need to have all dependencies installed as root. + +1. Install PHP dependencies: + + sudo apt-get update -qy + sudo apt-get install phpunit php5-mysql -y + + This will install the PHP version available for your distribution. + +2. Now you can run your tests. Usually it will be `phpunit` with arguments: + + test:app: + script: + - phpunit --configuration phpunit_myapp.xml --coverage-text + +#### Test against different PHP versions in Shell builds + +The [phpenv](https://github.com/phpenv/phpenv) allows you to easily manage different PHP with they own configs. +This is specially usefull when testing PHP project with Shell executor. + +Login as `gitlab-runner` user and follow [the installation guide](https://github.com/phpenv/phpenv#installation). + +Using phpenv also allows to easily configure PHP environment with: `phpenv config-add my_config.ini`. + +#### Install custom extensions + +Since we have pretty bare installation of our PHP environment you may need some extensions that are not present on your installation. + +To install additional extensions simply execute.: + + pecl install + + It's not advised to add this to the `.gitlab-ci.yml`. + You should execute this command once, only to setup the build environment. + +### Extend your tests + +#### Using atoum + +Instead of PHPUnit, you can use any other tool to run unit tests. For example [atoum](https://github.com/atoum/atoum): + + before_script: + - wget http://downloads.atoum.org/nightly/mageekguy.atoum.phar + + test:atoum: + script: + - php mageekguy.atoum.phar + +#### Using Composer + +Majority of the PHP projects use Composer for managing the packages. +It's very simple to execute the Composer before running your tests. +To your `.gitlab-ci.yml` add: + + # The composer stores all downloaded packages in vendor/ + # Remove it if you committed the vendor/ directory + cache: + paths: + - vendor/ + + before_script: + # Install composer dependencies + - curl -sS https://getcomposer.org/installer | php + - php composer.phar install + +### Access private packages / dependencies + +You need to configure [the SSH keys](../ssh_keys/README.md) in order to checkout the repositories. + +### Use databases or other services + +Please checkout the docs about configuring [the CI services](../services/README.md). + +### Example project + +You maybe interested in our [Example Project](https://gitlab.com/gitlab-examples/php) that runs on [GitLab.com](https://gitlab.com) using our publically available shared runners. + +Want to hack it? Simply fork it, commit and push changes. Within a few moments the changes will be picked and rebuilt by public runners. diff --git a/doc/ci/services/README.md b/doc/ci/services/README.md new file mode 100644 index 0000000000..0550e9435a --- /dev/null +++ b/doc/ci/services/README.md @@ -0,0 +1,6 @@ +## GitLab CI Services + ++ [Using MySQL](mysql.md) ++ [Using PostgreSQL](postgres.md) ++ [Using Redis](redis.md) ++ [Using Other Services](../docker/using_docker_images.html#how-to-use-other-images-as-services) diff --git a/doc/ci/services/docker-services.md b/doc/ci/services/docker-services.md new file mode 100644 index 0000000000..df36ebaf7d --- /dev/null +++ b/doc/ci/services/docker-services.md @@ -0,0 +1,5 @@ +## GitLab CI Services + ++ [Using MySQL](mysql.md) ++ [Using PostgreSQL](postgres.md) ++ [Using Redis](redis.md) diff --git a/doc/ci/services/mysql.md b/doc/ci/services/mysql.md new file mode 100644 index 0000000000..3155af6b3e --- /dev/null +++ b/doc/ci/services/mysql.md @@ -0,0 +1,72 @@ +## Using MySQL + +It's possible to use MySQL database test your apps during builds. + +### Use MySQL with Docker executor + +If you are using our Docker integration you basically have everything already. + +1. Add this to your `.gitlab-ci.yml`: + + services: + - mysql + + variables: + # Configure mysql service (https://hub.docker.com/_/mysql/) + MYSQL_DATABASE: hello_world_test + MYSQL_ROOT_PASSWORD: mysql + +2. Configure your application to use the database: + + Host: mysql + User: root + Password: mysql + Database: hello_world_test + +3. You can also use any other available on [DockerHub](https://hub.docker.com/_/mysql/). For example: `mysql:5.5`. + +Example: https://gitlab.com/gitlab-examples/mysql/blob/master/.gitlab-ci.yml + +### Use MySQL with Shell executor + +It's possible to use MySQL on manually configured servers that are using GitLab Runner with Shell executor. + +1. First install the MySQL server: + + sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev + + # Pick a MySQL root password (can be anything), type it and press enter + # Retype the MySQL root password and press enter + +2. Create an user: + + mysql -u root -p + + # Create a user which will be used by your apps + # do not type the 'mysql>', this is part of the prompt + # change $password in the command below to a real password you pick + mysql> CREATE USER 'runner'@'localhost' IDENTIFIED BY '$password'; + + # Ensure you can use the InnoDB engine which is necessary to support long indexes + # If this fails, check your MySQL config files (e.g. `/etc/mysql/*.cnf`, `/etc/mysql/conf.d/*`) for the setting "innodb = off" + mysql> SET storage_engine=INNODB; + + # Create the database + mysql> CREATE DATABASE IF NOT EXISTS `hello_world_test` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`; + + # Grant necessary permissions on the database + mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, CREATE TEMPORARY TABLES, DROP, INDEX, ALTER, LOCK TABLES ON `hello_world_test`.* TO 'runner'@'localhost'; + + # Quit the database session + mysql> \q + +3. Try to connect to database: + + sudo -u gitlab-runner -H mysql -u runner -p -D hello_world_test + +4. Configure your application to use the database: + + Host: localhost + User: runner + Password: $password + Database: hello_world_test diff --git a/doc/ci/services/postgres.md b/doc/ci/services/postgres.md new file mode 100644 index 0000000000..e57f8c5944 --- /dev/null +++ b/doc/ci/services/postgres.md @@ -0,0 +1,70 @@ +## Using PostgreSQL + +It's possible to use PostgreSQL database test your apps during builds. + +### Use PostgreSQL with Docker executor + +If you are using our Docker integration you basically have everything already. + +1. Add this to your `.gitlab-ci.yml`: + + services: + - postgres + + variables: + # Configure postgres service (https://hub.docker.com/_/postgres/) + POSTGRES_DB: hello_world_test + POSTGRES_USER: postgres + POSTGRES_PASSWORD: "" + +2. Configure your application to use the database: + + Host: postgres + User: postgres + Password: postgres + Database: hello_world_test + +3. You can also use any other available on [DockerHub](https://hub.docker.com/_/postgres/). For example: `postgres:9.3`. + +Example: https://gitlab.com/gitlab-examples/postgres/blob/master/.gitlab-ci.yml + +### Use PostgreSQL with Shell executor + +It's possible to use PostgreSQL on manually configured servers that are using GitLab Runner with Shell executor. + +1. First install the PostgreSQL server: + + sudo apt-get install -y postgresql postgresql-client libpq-dev + +2. Create an user: + + # Install the database packages + sudo apt-get install -y postgresql postgresql-client libpq-dev + + # Login to PostgreSQL + sudo -u postgres psql -d template1 + + # Create a user for runner + # Do not type the 'template1=#', this is part of the prompt + template1=# CREATE USER runner CREATEDB; + + # Create the database & grant all privileges on database + template1=# CREATE DATABASE hello_world_test OWNER runner; + + # Quit the database session + template1=# \q + +3. Try to connect to database: + + # Try connecting to the new database with the new user + sudo -u gitlab-runner -H psql -d hello_world_test + + # Quit the database session + hello_world_test> \q + +4. Configure your application to use the database: + + Host: localhost + User: runner + Password: + Database: hello_world_test diff --git a/doc/ci/services/redis.md b/doc/ci/services/redis.md new file mode 100644 index 0000000000..523634a457 --- /dev/null +++ b/doc/ci/services/redis.md @@ -0,0 +1,40 @@ +## Using Redis + +It's possible to use Redis database test your apps during builds. + +### Use Redis with Docker executor + +If you are using our Docker integration you basically have everything already. + +1. Add this to your `.gitlab-ci.yml`: + + services: + - redis + +2. Configure your application to use the database: + + Host: redis + +3. You can also use any other available on [DockerHub](https://hub.docker.com/_/redis/). For example: `redis:2.6`. + +Example: https://gitlab.com/gitlab-examples/redis/blob/master/.gitlab-ci.yml + +### Use Redis with Shell executor + +It's possible to use Redis on manually configured servers that are using GitLab Runner with Shell executor. + +1. First install the Redis server: + + sudo apt-get install redis-server + +2. Try to connect to the server: + + # Try connecting the the Redis server + sudo -u gitlab-runner -H redis-cli + + # Quit the session + 127.0.0.1:6379> quit + +4. Configure your application to use the database: + + Host: localhost diff --git a/doc/ci/ssh_keys/README.md b/doc/ci/ssh_keys/README.md new file mode 100644 index 0000000000..515194e5f5 --- /dev/null +++ b/doc/ci/ssh_keys/README.md @@ -0,0 +1,114 @@ +# Using SSH keys + +GitLab currently doesn't have built-in support for SSH keys in build environment. + +The SSH keys can be useful when: +1. You want to checkout internal submodules, +2. You want to download private packages using your package manager (ie. bundler), +3. You want to deploy your app (ex. to Heroku or own server), +4. You want to execute ssh commands from build environment on remote server, +5. You want to rsync files from your build to remote server. + +If anyone of the above holds true, then you most likely need SSH key. + +There are two possibilities to add SSH keys to build environment. + +## Inject keys in your build environment +The most widely supported is to inject SSH key into your build environment by extending your .gitlab-ci.yml. +This is the universal solution which works with any type of executor (docker, shell, etc.). + +### How it works? +1. We create a new SSH private key with [ssh-keygen](http://linux.die.net/man/1/ssh-keygen). +2. We add the private key as the Secure Variable to project. +3. We run the [ssh-agent](http://linux.die.net/man/1/ssh-agent) during build to load the private key. + +The example [.gitlab-ci.yml](https://gitlab.com/gitlab-examples/ssh-private-key/blob/master/.gitlab-ci.yml) looks like this. + +### Make it work? +1. First, go to terminal and generate a new SSH key: +```bash +$ ssh-keygen -t rsa -f my_key + +Generating public/private rsa key pair. +Enter passphrase (empty for no passphrase): +Enter same passphrase again: +Your identification has been saved in my_key. +Your public key has been saved in my_key.pub. +The key fingerprint is: +SHA256:tBJEfyJUGTMNmPCiPg4UHywHs67MxlM2iEBAlI/W+TY fingeprint +The key's randomart image is: ++---[RSA 2048]----+ +|=*. .o++*= | +|..= +o..o. | +|.+++o + + . | +|+o*=.. + + | +|o+.=. . S | +|*.o .E . | +|o*o . . | +|.o.. | +| . | ++----[SHA256]-----+ +``` + +2. Create a new **Secure Variable** in your project settings on GitLab and name it: `SSH_PRIVATE_KEY`. + +3. Copy the content of `my_key` and paste it as a **Value** of **SSH_PRIVATE_KEY**. + +4. Next you need to modify your `.gitlab-ci.yml` and at the top of the file add: +``` +before_script: +# install ssh-agent (it is required for Docker, change apt-get to yum if you use CentOS-based image) +- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' + +# run ssh-agent (in build environment) +- eval $(ssh-agent -s) + +# add ssh key stored in SSH_PRIVATE_KEY variable to the agent store +- ssh-add <(echo "$SSH_PRIVATE_KEY") + +# for Docker builds disable host key checking, by adding that you are suspectible to man-in-the-middle attack +- mkdir -p ~/.ssh +- '[[ -f /.dockerinit ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config` +``` + +5. Add the public key from `my_key.pub` to services that you want to have an access from build. + +6. If your builds are run using `shell` executor, you may need to login to server and execute the `ssh ` to store the fingerprint of remote server. + +## SSH keys when using Shell executor +If use `shell`, not `docker` it can be easier to have the SSH key. + +We can generate the SSH key for the machine that holds `gitlab-runner` and use that key for all projects that are run on this machine. + +1. First, login to server that runs your builds. + +2. From terminal login as `gitlab-runner` user and generate the SSH private key: +```bash +$ ssh-keygen -t rsa +Generating public/private rsa key pair. +Enter passphrase (empty for no passphrase): +Enter same passphrase again: +Your identification has been saved in ~/.ssh/id_rsa. +Your public key has been saved in ~/.ssh/id_rsa.pub. +The key fingerprint is: +SHA256:tBJEfyJUGTMNmPCiPg4UHywHs67MxlM2iEBAlI/W+TY fingeprint +The key's randomart image is: ++---[RSA 2048]----+ +|=*. .o++*= | +|..= +o..o. | +|.+++o + + . | +|+o*=.. + + | +|o+.=. . S | +|*.o .E . | +|o*o . . | +|.o.. | +| . | ++----[SHA256]-----+ +``` + +3. Add the public key from `~/.ssh/id_rsa.pub` to services that you want to have an access from build. + +4. Try to login for the first time and accept fingerprint: +```bash +ssh Date: Wed, 2 Dec 2015 17:47:18 +0200 Subject: [PATCH 17/42] Fix heading --- doc/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/README.md b/doc/README.md index a7025f7af1..f85a464a4f 100644 --- a/doc/README.md +++ b/doc/README.md @@ -32,7 +32,7 @@ + [Testing PHP](ci/languages/php.md) -## CI Services +### CI Services + [Using MySQL](ci/services/mysql.md) + [Using PostgreSQL](ci/services/postgres.md) From dcdc49fe429c0e8a762f1a411e1d5c0a7294c91f Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Wed, 2 Dec 2015 19:24:15 +0200 Subject: [PATCH 18/42] Use .md instead of .html --- doc/README.md | 2 +- doc/ci/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/README.md b/doc/README.md index f85a464a4f..a309809421 100644 --- a/doc/README.md +++ b/doc/README.md @@ -37,7 +37,7 @@ + [Using MySQL](ci/services/mysql.md) + [Using PostgreSQL](ci/services/postgres.md) + [Using Redis](ci/services/redis.md) -+ [Using Other Services](ci/docker/using_docker_images.html#how-to-use-other-images-as-services) ++ [Using Other Services](ci/docker/using_docker_images.md#how-to-use-other-images-as-services) ### CI Examples diff --git a/doc/ci/README.md b/doc/ci/README.md index ae921b6f98..5d9d7a81db 100644 --- a/doc/ci/README.md +++ b/doc/ci/README.md @@ -20,7 +20,7 @@ + [Using MySQL](services/mysql.md) + [Using PostgreSQL](services/postgres.md) + [Using Redis](services/redis.md) -+ [Using Other Services](docker/using_docker_images.html#how-to-use-other-images-as-services) ++ [Using Other Services](docker/using_docker_images.md#how-to-use-other-images-as-services) ### Examples From 05267b64d224c19f1b6843a715f666aea2bd106a Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 3 Dec 2015 00:36:45 +0200 Subject: [PATCH 19/42] Clean up using_docker_images.md --- doc/ci/docker/using_docker_images.md | 272 ++++++++++++++++++--------- 1 file changed, 187 insertions(+), 85 deletions(-) diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index 2f0ca19cd0..6551d47b69 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -1,16 +1,25 @@ # Using Docker Images -GitLab CI can use [Docker Engine](https://www.docker.com/) to build projects. -Docker is an open-source project that allows to use predefined images to run applications -in independent "containers" that are run within a single Linux instance. -[Docker Hub](https://registry.hub.docker.com/) have rich database of built images that can be used to build applications. +GitLab CI can use [Docker Engine](https://www.docker.com/) to build projects. -Docker when used with GitLab CI runs each build in separate and isolated container using predefined image and always from scratch. -It makes it easier to have simple and reproducible build environment that can also be run on your workstation. -This allows you to test all commands from your shell, rather than having to test them on a CI server. +Docker is an open-source project that allows to use predefined images to run +applications in independent "containers" that are run within a single Linux +instance. [Docker Hub][hub] has a rich database of prebuilt images that can be +used to test and build your applications. -### Register Docker runner -To use GitLab Runner with Docker you need to register new runner to use `docker` executor: +Docker, when used with GitLab CI, runs each build in a separate and isolated +container using the predefined image that is set up in `.gitlab-ci.yml`. The +container is always euphemeral which means you get only one container per build. + +This makes it easier to have a simple and reproducible build environment that +can also run on your workstation. The added benefit is that you can test all +the commands that we will explore later from your shell, rather than having to +test them on a CI server. + +### Register docker runner + +To use GitLab Runner with docker you need to register a new runner to use the +`docker` executor: ```bash gitlab-ci-multi-runner register \ @@ -23,45 +32,70 @@ gitlab-ci-multi-runner register \ --docker-mysql latest ``` -**The registered runner will use `ruby:2.1` image and will run two services (`postgres:latest` and `mysql:latest`) that will be accessible for time of the build.** +The registered runner will use the `ruby:2.1` docker image and will run two +services, `postgres:latest` and `mysql:latest`, both of which will be +accessible during the build process. -### What is image? -The image is the name of any repository that is present in local Docker Engine or any repository that can be found at [Docker Hub](https://registry.hub.docker.com/). -For more information about the image and Docker Hub please read the [Docker Fundamentals](https://docs.docker.com/introduction/understanding-docker/). +### What is image -### What is service? -Service is just another image that is run for time of your build and is linked to your build. This allows you to access the service image during build time. -The service image can run any application, but most common use case is to run some database container, ie.: `mysql`. -It's easier and faster to use existing image, run it as additional container than install `mysql` every time project is built. +The `image` keyword is the name of the docker image that is present in the +local Docker Engine (list all images with `docker images`) or any image that +can be found at [Docker Hub][hub]. For more information about images and Docker +Hub please read the [Docker Fundamentals][] documentation. -#### How is service linked to the build? -There's good document that describes how Docker linking works: [Linking containers together](https://docs.docker.com/userguide/dockerlinks/). -To summarize: if you add `mysql` as service to your application, the image will be used to create container that is linked to build container. -The service container for MySQL will be accessible under hostname `mysql`. -So, **to access your database service you have to connect to host: `mysql` instead of socket or `localhost`**. +In short, with `image` we refer to the docker image, which will be used to +create a container on which your build will run. -### How to use other images as services? -You are not limited to have only database services. -You can add the services to `.gitlab-ci.yml` or hand modify the `config.toml`. -You can use any image as service found at [Docker Hub](https://registry.hub.docker.com/). +### What is service + +The `service` keyword defines just another docker image that is run during +your build and is linked to the docker image that the `image` keyword defines. +This allows you to access the service image during build time. + +The service image can run any application, but the most common use case is to +run a database container, eg. `mysql`. It's easier and faster to use an +existing image and run it as an additional container than install `mysql` every +time the project is built. + +#### How is service linked to the build + +To better undestand how the container linking works, read +[Linking containers together](https://docs.docker.com/userguide/dockerlinks/). + +To summarize, if you add `mysql` as service to your application, the image will +then be used to create a container that is linked to the build container. + +The service container for MySQL will be accessible under the hostname `mysql`. +So, in order to access your database service you have to connect to the host +named `mysql` instead of a socket or `localhost`. + +### How to use other images as services + +You are not limited to have only database services. You can add as many +services you need to `.gitlab-ci.yml` or manually modify `config.toml`. +Any image found at [Docker Hub][hub] can be used as a service. ### Define image and services from `.gitlab-ci.yml` -You can simply define image or list services that you want to use for the build time. -``` + +You can simply define an image that will be used for all jobs and a list of +services that you want to use during build time. + +```yaml image: ruby:2.2 services: - postgres:9.3 -before_install: +before_script: - bundle install - + test: script: - bundle exec rake spec ``` -It's possible to define image and service per-job: -``` -before_install: +It is also possible to define different images and services per job: + +```yaml +before_script: - bundle install test:2.1: @@ -80,68 +114,106 @@ test:2.2: ``` ### Define image and services in `config.toml` -Look for `[runners.docker]` section: + +Look for the `[runners.docker]` section: + ``` +... + [runners.docker] image = "ruby:2.1" services = ["mysql:latest", "postgres:latest"] + +... ``` -The image and services defined these way will be added to all builds run by that runner. +The image and services defined this way will be added to all builds run by +that runner. ### Accessing the services -For example you need `wordpress` instance to test some API integration with `Wordpress`. -You can for example use this image: [tutum/wordpress](https://registry.hub.docker.com/u/tutum/wordpress/). -``` -# .gitlab-ci.yml +Let's say that you need a Wordpress instance to test some API integration with +your application. + +You can then use for example the [tutum/wordpress][] image in your +`.gitlab-ci.yml`: + +```yaml +... + services: - tutum/wordpress:latest + +... ``` -Next time when you run your application the `tutum/wordpress` will be started -and you will have access to it from your build container under hostname: `tutum__wordpress`. +When the build is run, `tutum/wordpress` will be started and you will have +access to it from your build container under the hostname `tutum_wordpress`. -Alias hostname for the service is made from the image name: -1. Everything after `:` is stripped, -2. '/' is replaced to `__`. +The alias hostname for the service is made from the image name following these +rules: + +1. Everything after `:` is stripped +2. Backslash (`/`) is replaced with double underscores (`__`) ### Configuring services -Many services accept environment variables, which allow you to easily change database names or set account names depending on the environment. -GitLab Runner 0.5.0 and up passes all YAML-defined variables to created service containers. +Many services accept environment variables which allow you to easily change +database names or set account names depending on the environment. -1. To configure database name for [postgres](https://registry.hub.docker.com/u/library/postgres/) service, -you need to set POSTGRES_DB. +GitLab Runner 0.5.0 and up passes all YAML-defined variables to the created +service containers. - ```yaml - services: - - postgres - - variables: - POSTGRES_DB: gitlab - ``` +For all possible configuration variables check the documentation of each image +provided in their corresponding Docker hub page. -1. To use [mysql](https://registry.hub.docker.com/u/library/mysql/) service with empty password for time of build, -you need to set MYSQL_ALLOW_EMPTY_PASSWORD. +*Note: All variables will be passed to all service containers. It's not designed + to distinguish which variable should go where.* - ```yaml - services: - - mysql - - variables: - MYSQL_ALLOW_EMPTY_PASSWORD: "yes" - ``` +#### PostgreSQL service example -For other possible configuration variables check the -https://registry.hub.docker.com/u/library/mysql/ or https://registry.hub.docker.com/u/library/postgres/ -or README page for any other Docker image. +To configure the database name for [postgres][postgres-hub] service, you need +to set the `POSTGRES_DB` variable: -**Note: All variables will passed to all service containers. It's not designed to distinguish which variable should go where.** +```yaml +... + +services: +- postgres + +variables: + POSTGRES_DB: gitlab + +... +``` + +For a real example visit . + +#### MySQL service example + +To use the [mysql][mysql-hub] service with an empty password during the time of +build, you need to set the `MYSQL_ALLOW_EMPTY_PASSWORD` variable: + +```yaml +... + +services: +- mysql + +variables: + MYSQL_ALLOW_EMPTY_PASSWORD: "yes" + +... +``` ### How Docker integration works + +Below is a high level overview of the steps performed by docker during build +time. + 1. Create any service container: `mysql`, `postgresql`, `mongodb`, `redis`. -1. Create cache container to store all volumes as defined in `config.toml` and `Dockerfile` of build image (`ruby:2.1` as in above example). +1. Create cache container to store all volumes as defined in `config.toml` and + `Dockerfile` of build image (`ruby:2.1` as in above example). 1. Create build container and link any service container to build container. 1. Start build container and send build script to the container. 1. Run build script. @@ -151,32 +223,62 @@ or README page for any other Docker image. 1. Remove build container and all created service containers. ### How to debug a build locally -1. Create a file with build script: + +*Note: The following commands are run without root privileges. You should be +able to run docker with your regular user account.* + +First start with creating a file named `build script`: + ```bash -$ cat < build_script +cat < build_script git clone https://gitlab.com/gitlab-org/gitlab-ci-multi-runner.git /builds/gitlab-org/gitlab-ci-multi-runner cd /builds/gitlab-org/gitlab-ci-multi-runner -make <- or any other build step +make EOF ``` -1. Create service containers: -``` -$ docker run -d -n service-mysql mysql:latest -$ docker run -d -n service-postgres postgres:latest -``` -This will create two service containers (MySQL and PostgreSQL). +Here we use as an example the GitLab Runner repository which contains a +Makefile, so running `make` will execute the commands defined in the Makefile. +Your mileage may vary, so instead of `make` you could run the command which +is specific to your project. -1. Create a build container and execute script in its context: +Then create some service containers: + ``` -$ docker run --name build -i --link=service-mysql:mysql --link=service-postgres:postgres ruby:2.1 /bin/bash < build_script +docker run -d -n service-mysql mysql:latest +docker run -d -n service-postgres postgres:latest ``` -This will create build container that has two service containers linked. -The build_script is piped using STDIN to bash interpreter which executes the build script in container. + +This will create two service containers, named `service-mysql` and +`service-postgres` which use the latest MySQL and PostgreSQL images +respectively. They will both run in the background (`-d`). + +Finally, create a build container by executing the `build_script` file we +created earlier: + +``` +docker run --name build -i --link=service-mysql:mysql --link=service-postgres:postgres ruby:2.1 /bin/bash < build_script +``` + +The above command will create a container named `build` that is spawned from +the `ruby:2.1` image and has two services linked to it. The `build_script` is +piped using STDIN to the bash interpreter which in turn executes the +`build_script` in the `build` container. + +When you finish testing and no longer need the containers, you can remove them +with: -1. At the end remove all containers: ``` docker rm -f -v build service-mysql service-postgres ``` -This will forcefully (the `-f` switch) remove build container and service containers -and all volumes (the `-v` switch) that were created with the container creation. + +This will forcefully (`-f`) remove the `build` container, the two service +containers as well as all volumes (`-v`) that were created with the container +creation. + +[Docker Fundamentals]: https://docs.docker.com/engine/introduction/understanding-docker/ +[hub]: https://hub.docker.com/ +[linking-containers]: https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/ +[tutum/wordpress]: https://registry.hub.docker.com/u/tutum/wordpress/ +[postgres-hub]: https://registry.hub.docker.com/u/library/postgres/ +[mysql-hub]: https://registry.hub.docker.com/u/library/mysql/ From 223a02757909b406c1d5ebe42ca4bc3340318a2e Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 3 Dec 2015 15:43:06 +0200 Subject: [PATCH 20/42] Bring back removed heading and point to other section --- doc/ci/docker/using_docker_images.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index 6551d47b69..63cfa43633 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -69,6 +69,10 @@ The service container for MySQL will be accessible under the hostname `mysql`. So, in order to access your database service you have to connect to the host named `mysql` instead of a socket or `localhost`. +### Overwrite image and services + +See the section below. + ### How to use other images as services You are not limited to have only database services. You can add as many From 71519d650d0317785f86ed935508d1dd5966cd6e Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 3 Dec 2015 15:43:29 +0200 Subject: [PATCH 21/42] Fix wrong example --- doc/ci/docker/using_docker_images.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index 63cfa43633..488479418b 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -152,7 +152,7 @@ services: ``` When the build is run, `tutum/wordpress` will be started and you will have -access to it from your build container under the hostname `tutum_wordpress`. +access to it from your build container under the hostname `tutum__wordpress`. The alias hostname for the service is made from the image name following these rules: From bb75dfe38b481607952234212a15d29cd17b7cef Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 3 Dec 2015 15:46:27 +0200 Subject: [PATCH 22/42] Add intro about languages --- doc/ci/languages/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/ci/languages/README.md b/doc/ci/languages/README.md index 375adf58d1..54b2343e08 100644 --- a/doc/ci/languages/README.md +++ b/doc/ci/languages/README.md @@ -1,3 +1,7 @@ ### Languages +This is a list of languages you can test with GitLab CI. Each section has +comprehensive documentation and comes with a test repository hosted on +GitLab.com + + [Testing PHP](php.md) From a08cc70232b1c5071f199106a582c77ba9541a83 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 3 Dec 2015 18:13:19 +0200 Subject: [PATCH 23/42] Clean up PHP CI example [ci skip] --- doc/ci/languages/php.md | 325 ++++++++++++++++++++++++++-------------- 1 file changed, 211 insertions(+), 114 deletions(-) diff --git a/doc/ci/languages/php.md b/doc/ci/languages/php.md index e058918200..c71ae40786 100644 --- a/doc/ci/languages/php.md +++ b/doc/ci/languages/php.md @@ -1,178 +1,275 @@ -## Testing PHP projects +# Testing PHP projects -This guide covers basic of building PHP projects. +This guide covers basic building instructions for PHP projects. -Is it possible to test PHP apps on any system. -However, it will require manual configuration. -The simplest is to use Docker executor as described below. +There are covered two cases: testing using the Docker executor and testing +using the Shell executor. -### PHP projects on Docker executor -It's possible to official [PHP](https://hub.docker.com/_/php/) repositories on Docker Hub. -They allow to test PHP projects against different versions of the runtime. -However, they require additional configuration. +## Test PHP projects using the Docker executor -To build PHP project you need to create valid `.gitlab-ci.yml` describing the build environment: -1. First you need to specify PHP image as described here: http://doc.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-image. To your `.gitlab-ci.yml` add: +While it is possible to test PHP apps on any system, this would require manual +configuration from the developer. To overcome this we will be using the +official [PHP docker image][php-hub] that can be found in Docker Hub. - image: php:5.6 +This will allow us to test PHP projects against different versions of PHP. +However, not everything is plug 'n' play, you still need to onfigure some +things manually. -2. The official images are great, but they are lacking a few useful tools for testing. We need to install them first in build environment. Create `ci/docker_install.sh` file with following content: +As with every build, you need to create a valid `.gitlab-ci.yml` describing the +build environment. - #!/bin/bash +Let's first specify the PHP image that will be used for the build process +(you can read more about what an image means in the Runner's lingo reading +about [Using Docker images](../docker/using_docker_images.md#what-is-image)). - # We need to install dependencies only for Docker - [[ ! -e /.dockerinit ]] && exit 0 +Start by adding the image to your `.gitlab-ci.yml`: - set -xe +```yaml +image: php:5.6 +``` - # Install git (the php image doesn't have it) which is required by composer - apt-get update -yqq - apt-get install git -yqq +The official images are great, but they lack a few useful tools for testing. +We need to first prepare the build environment. A way to overcome this is to +create a script which installs all prerequisites prior the actual testing is +done. - # Install phpunit, the tool that we will use for testing - curl -o /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar - chmod +x /usr/local/bin/phpunit +Let's create a `ci/docker_install.sh` file in the root directory of our +repository with the following content: - # Install mysql driver - # Here you can install any other extension that you need - docker-php-ext-install pdo_mysql +```bash +#!/bin/bash -3. From your `.gitlab-ci.yml` run the created script: +# We need to install dependencies only for Docker +[[ ! -e /.dockerinit ]] && exit 0 - before_script: - - bash ci/docker_install.sh > /dev/null +set -xe -4. Now you can run your tests. Usually it will be `phpunit` with arguments: +# Install git (the php image doesn't have it) which is required by composer +apt-get update -yqq +apt-get install git -yqq - test:app: - script: - - phpunit --configuration phpunit_myapp.xml --coverage-text +# Install phpunit, the tool that we will use for testing +curl -o /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar +chmod +x /usr/local/bin/phpunit -5. Commit your files, and push them to GitLab to see if it works. With GitLab Runner 1.0 you can also test the changes locally. From your terminal execute: +# Install mysql driver +# Here you can install any other extension that you need +docker-php-ext-install pdo_mysql +``` - # Check using docker executor - gitlab-runner exec docker test:app +You might wonder what `docker-php-ext-install` is. In short, it is a script +provided by the official php docker image that you can use to easilly install +extensions. For more information read the the documentation at +. - # Check using shell executor - gitlab-runner exec shell test:app +Now that we created the script that contains all prerequisites for our build +environment, let's add it in `.gitlab-ci.yml`: + +```yaml +... + +before_script: +- bash ci/docker_install.sh > /dev/null + +... +``` + +Last step, run the actual tests using `phpunit`: + +```yaml +... + +test:app: + script: + - phpunit --configuration phpunit_myapp.xml + +... +``` + +Finally, commit your files and push them to GitLab to see your build succeeding +(or failing). The final `.gitlab-ci.yml` should look similar to this: - # Select image from https://hub.docker.com/_/php/ - image: php:5.6 +```yaml +# Select image from https://hub.docker.com/_/php/ +image: php:5.6 - before_script: - # Install dependencies - - ci/docker_install.sh > /dev/null +before_script: +# Install dependencies +- ci/docker_install.sh > /dev/null - test:app: - script: - - phpunit --configuration phpunit_myapp.xml --coverage-text +test:app: + script: + - phpunit --configuration phpunit_myapp.xml +``` -#### Test against different PHP versions in Docker builds +### Test against different PHP versions in Docker builds -You can also test against multiple version of PHP runtime: +Testing against multiple versions of PHP is super easy. Just add another job +with a different docker image version and the runner will do the rest: - before_script: - # Install dependencies - - ci/docker_install.sh > /dev/null +```yaml +before_script: +# Install dependencies +- ci/docker_install.sh > /dev/null - # We test PHP5.6 - test:5.6: - image: php:5.6 - script: - - phpunit --configuration phpunit_myapp.xml --coverage-text +# We test PHP5.6 +test:5.6: + image: php:5.6 + script: + - phpunit --configuration phpunit_myapp.xml - # We test PHP7.0 - test:7.0: - image: php:7.0 - script: - - phpunit --configuration phpunit_myapp.xml --coverage-text +# We test PHP7.0 (good luck with that) +test:7.0: + image: php:7.0 + script: + - phpunit --configuration phpunit_myapp.xml +``` -#### Custom PHP configuration in Docker builds +### Custom PHP configuration in Docker builds -You can customise your PHP environment by putting your .ini file into `/usr/local/etc/php/conf.d/`: +There are times where you will need to customise your PHP environment by +putting your `.ini` file into `/usr/local/etc/php/conf.d/`. For that purpose +add a `before_script` action: - before_script: - - cp my_php.ini /usr/local/etc/php/conf.d/test.ini +```yaml +before_script: +- cp my_php.ini /usr/local/etc/php/conf.d/test.ini +``` -### Test PHP projects using Shell +Of course, `my_php.ini` must be present in the root directory of your repository. -Shell executor runs your builds in terminal session of your server. Thus in order to test your projects you need to have all dependencies installed as root. +## Test PHP projects using the Shell executor -1. Install PHP dependencies: +The shell executor runs your builds in a terminal session on your server. +Thus, in order to test your projects you first need to make sure that all +dependencies are installed. - sudo apt-get update -qy - sudo apt-get install phpunit php5-mysql -y +For example, in a VM running Debian 8 we first update the cache, then we +install `phpunit` and `php5-mysql`: - This will install the PHP version available for your distribution. +```bash +sudo apt-get update -y +sudo apt-get install -y phpunit php5-mysql +``` -2. Now you can run your tests. Usually it will be `phpunit` with arguments: +Next, add the following snippet to your `.gitlab-ci.yml`: - test:app: - script: - - phpunit --configuration phpunit_myapp.xml --coverage-text +```yaml +test:app: + script: + - phpunit --configuration phpunit_myapp.xml +``` -#### Test against different PHP versions in Shell builds +Finally, push to GitLab and let the tests begin! -The [phpenv](https://github.com/phpenv/phpenv) allows you to easily manage different PHP with they own configs. -This is specially usefull when testing PHP project with Shell executor. +### Test against different PHP versions in Shell builds -Login as `gitlab-runner` user and follow [the installation guide](https://github.com/phpenv/phpenv#installation). +The [phpenv][] project allows you to easily manage different versions of PHP +each with its own config. This is specially usefull when testing PHP projects +with the Shell executor. -Using phpenv also allows to easily configure PHP environment with: `phpenv config-add my_config.ini`. +You will have to install it on your build machine under the `gitlab-runner` +user following [the upstream installation guide][phpenv-installation]. -#### Install custom extensions +Using phpenv also allows to easily configure the PHP environment with: -Since we have pretty bare installation of our PHP environment you may need some extensions that are not present on your installation. +``` +phpenv config-add my_config.ini +``` -To install additional extensions simply execute.: +### Install custom extensions - pecl install +Since this is a pretty bare installation of the PHP environment, you may need +some extensions that are not currently present on the build machine. - It's not advised to add this to the `.gitlab-ci.yml`. - You should execute this command once, only to setup the build environment. +To install additional extensions simply execute: -### Extend your tests +```bash +pecl install +``` -#### Using atoum +It's not advised to add this to `.gitlab-ci.yml`. You should execute this +command once, only to setup the build environment. -Instead of PHPUnit, you can use any other tool to run unit tests. For example [atoum](https://github.com/atoum/atoum): +## Extend your tests - before_script: - - wget http://downloads.atoum.org/nightly/mageekguy.atoum.phar +### Using atoum - test:atoum: - script: - - php mageekguy.atoum.phar +Instead of PHPUnit, you can use any other tool to run unit tests. For example +you can use [atoum](https://github.com/atoum/atoum): -#### Using Composer +```yaml +before_script: +- wget http://downloads.atoum.org/nightly/mageekguy.atoum.phar -Majority of the PHP projects use Composer for managing the packages. -It's very simple to execute the Composer before running your tests. -To your `.gitlab-ci.yml` add: +test:atoum: + script: + - php mageekguy.atoum.phar +``` - # The composer stores all downloaded packages in vendor/ - # Remove it if you committed the vendor/ directory - cache: - paths: - - vendor/ +### Using Composer - before_script: - # Install composer dependencies - - curl -sS https://getcomposer.org/installer | php - - php composer.phar install +The majority of the PHP projects use Composer for managing their PHP packages. +In order to execute Composer before running your tests, simply add the +following in your `.gitlab-ci.yml`: -### Access private packages / dependencies +```yaml +... -You need to configure [the SSH keys](../ssh_keys/README.md) in order to checkout the repositories. +# Composer stores all downloaded packages in the vendor/ directory. +# Do not use the following if the vendor/ directory is commited to +# your git repository. +cache: + paths: + - vendor/ -### Use databases or other services +before_script: +# Install composer dependencies +- curl -sS https://getcomposer.org/installer | php +- php composer.phar install -Please checkout the docs about configuring [the CI services](../services/README.md). +... +``` -### Example project +## Access private packages / dependencies -You maybe interested in our [Example Project](https://gitlab.com/gitlab-examples/php) that runs on [GitLab.com](https://gitlab.com) using our publically available shared runners. +If your test suite needs to access a private repository, you need to configure +[the SSH keys](../ssh_keys/README.md) in order to be able to clone it. -Want to hack it? Simply fork it, commit and push changes. Within a few moments the changes will be picked and rebuilt by public runners. +## Use databases or other services + +Most of the time you will need a running database in order for your tests to +run. If you are using the Docker executor you can leverage Docker's ability to +connect to other containers. In GitLab Runner lingo, this can be achieved by +defining a `service`. + +This functionality is covered in [the CI services](../services/README.md) +documentation. + +## Testing things locally + +With GitLab Runner 1.0 you can also test any changes locally. From your +terminal execute: + +```bash +# Check using docker executor +gitlab-runner exec docker test:app + +# Check using shell executor +gitlab-runner exec shell test:app +``` + +## Example project + +We have set up an [Example PHP Project](https://gitlab.com/gitlab-examples/php) +for your convenience that runs on [GitLab.com](https://gitlab.com) using our +publicly available [shared runners](../runners/README.md). + +Want to hack it? Simply fork it, commit and push your changes. Within a few +moments the changes will be picked by a public runner and the build will begin. + +[php-hub]: https://hub.docker.com/_/php/ +[phpenv]: https://github.com/phpenv/phpenv +[phpenv-installation]: https://github.com/phpenv/phpenv#installation From 9b8babb601ac6bdb3b7301b017a8ce20c5dc4814 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 3 Dec 2015 21:18:34 +0200 Subject: [PATCH 24/42] Use link instead of connect to be more Docker friendly --- doc/ci/languages/php.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/languages/php.md b/doc/ci/languages/php.md index c71ae40786..589253cfc4 100644 --- a/doc/ci/languages/php.md +++ b/doc/ci/languages/php.md @@ -242,7 +242,7 @@ If your test suite needs to access a private repository, you need to configure Most of the time you will need a running database in order for your tests to run. If you are using the Docker executor you can leverage Docker's ability to -connect to other containers. In GitLab Runner lingo, this can be achieved by +link to other containers. In GitLab Runner lingo, this can be achieved by defining a `service`. This functionality is covered in [the CI services](../services/README.md) From d13d43aca9c486365fbe6eab8d30cb1e005c3f61 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Fri, 4 Dec 2015 11:46:08 +0200 Subject: [PATCH 25/42] Clean up CI ssh keys docs [ci skip] --- doc/ci/ssh_keys/README.md | 163 ++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 84 deletions(-) diff --git a/doc/ci/ssh_keys/README.md b/doc/ci/ssh_keys/README.md index 515194e5f5..210f9c3e84 100644 --- a/doc/ci/ssh_keys/README.md +++ b/doc/ci/ssh_keys/README.md @@ -1,114 +1,109 @@ # Using SSH keys -GitLab currently doesn't have built-in support for SSH keys in build environment. +GitLab currently doesn't have built-in support for managing SSH keys in a build +environment. The SSH keys can be useful when: -1. You want to checkout internal submodules, -2. You want to download private packages using your package manager (ie. bundler), -3. You want to deploy your app (ex. to Heroku or own server), -4. You want to execute ssh commands from build environment on remote server, -5. You want to rsync files from your build to remote server. -If anyone of the above holds true, then you most likely need SSH key. +1. You want to checkout internal submodules +2. You want to download private packages using your package manager (eg. bundler) +3. You want to deploy your application to eg. Heroku or your own server +4. You want to execute SSH commands from the build server to the remote server +5. You want to rsync files from your build server to the remote server -There are two possibilities to add SSH keys to build environment. +If anything of the above rings a bell, then you most likely need an SSH key. -## Inject keys in your build environment -The most widely supported is to inject SSH key into your build environment by extending your .gitlab-ci.yml. -This is the universal solution which works with any type of executor (docker, shell, etc.). +## Inject keys in your build server -### How it works? -1. We create a new SSH private key with [ssh-keygen](http://linux.die.net/man/1/ssh-keygen). -2. We add the private key as the Secure Variable to project. -3. We run the [ssh-agent](http://linux.die.net/man/1/ssh-agent) during build to load the private key. +The most widely supported method is to inject an SSH key into your build +environment by extending your `.gitlab-ci.yml`. -The example [.gitlab-ci.yml](https://gitlab.com/gitlab-examples/ssh-private-key/blob/master/.gitlab-ci.yml) looks like this. +This is the universal solution which works with any type of executor +(docker, shell, etc.). -### Make it work? -1. First, go to terminal and generate a new SSH key: -```bash -$ ssh-keygen -t rsa -f my_key +### How it works -Generating public/private rsa key pair. -Enter passphrase (empty for no passphrase): -Enter same passphrase again: -Your identification has been saved in my_key. -Your public key has been saved in my_key.pub. -The key fingerprint is: -SHA256:tBJEfyJUGTMNmPCiPg4UHywHs67MxlM2iEBAlI/W+TY fingeprint -The key's randomart image is: -+---[RSA 2048]----+ -|=*. .o++*= | -|..= +o..o. | -|.+++o + + . | -|+o*=.. + + | -|o+.=. . S | -|*.o .E . | -|o*o . . | -|.o.. | -| . | -+----[SHA256]-----+ -``` +1. Create a new SSH key pair with [ssh-keygen][] +2. Add the private key as a **Secret Variable** to the project +3. Run the [ssh-agent][] during build to load the private key. -2. Create a new **Secure Variable** in your project settings on GitLab and name it: `SSH_PRIVATE_KEY`. +## SSH keys when using the Docker executor -3. Copy the content of `my_key` and paste it as a **Value** of **SSH_PRIVATE_KEY**. +You will first need to create an SSH key pair. For more information, follow the +instructions to [generate an SSH key](../ssh/README.md). + +Then, create a new **Secret Variable** in your project settings on GitLab +following **Settings > Variables**. As **Key** add the name `SSH_PRIVATE_KEY` +and in the **Value** field paste the content of your _private_ key that you +created earlier. + +Next you need to modify your `.gitlab-ci.yml` with a `before_script` action. +Add it to the top: -4. Next you need to modify your `.gitlab-ci.yml` and at the top of the file add: ``` before_script: -# install ssh-agent (it is required for Docker, change apt-get to yum if you use CentOS-based image) -- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' + # Install ssh-agent if not already installed, it is required by Docker. + # (change apt-get to yum if you use a CentOS-based image) + - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' -# run ssh-agent (in build environment) -- eval $(ssh-agent -s) + # Run ssh-agent (inside the build environment) + - eval $(ssh-agent -s) -# add ssh key stored in SSH_PRIVATE_KEY variable to the agent store -- ssh-add <(echo "$SSH_PRIVATE_KEY") + # Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store + - ssh-add <(echo "$SSH_PRIVATE_KEY") -# for Docker builds disable host key checking, by adding that you are suspectible to man-in-the-middle attack -- mkdir -p ~/.ssh -- '[[ -f /.dockerinit ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config` + # For Docker builds disable host key checking. Be aware that by adding that + # you are suspectible to man-in-the-middle attacks. + # WARNING: Use this only with the Docker executor, if you use it with shell + # you will overwrite your user's SSH config. + - mkdir -p ~/.ssh + - '[[ -f /.dockerinit ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config` ``` -5. Add the public key from `my_key.pub` to services that you want to have an access from build. +As a final step, add the _public_ key from the one you created earlier to the +services that you want to have an access to from within the build environment. +If you are accessing a private GitLab repository you need to add it as a +[deploy key](../ssh/README.md#deploy-keys). -6. If your builds are run using `shell` executor, you may need to login to server and execute the `ssh ` to store the fingerprint of remote server. +That's it! You can now have access to private servers or repositories in your +build environment. -## SSH keys when using Shell executor -If use `shell`, not `docker` it can be easier to have the SSH key. +## SSH keys when using the Shell executor -We can generate the SSH key for the machine that holds `gitlab-runner` and use that key for all projects that are run on this machine. +If you are using the Shell executor and not Docker, it is easier to set up an +SSH key. -1. First, login to server that runs your builds. +You can generate the SSH key from the machine that GitLab Runner is installed +on, and use that key for all projects that are run on this machine. + +First, you need to login to the server that runs your builds. + +Then from the terminal login as the `gitlab-runner` user and generate the SSH +key pair as described in the [SSH keys documentation](../ssh/README.md). + +As a final step, add the _public_ key from the one you created earlier to the +services that you want to have an access to from within the build environment. +If you are accessing a private GitLab repository you need to add it as a +[deploy key](../ssh/README.md#deploy-keys). + +Once done, try to login to the remote server in order to accept the fingerprint: -2. From terminal login as `gitlab-runner` user and generate the SSH private key: ```bash -$ ssh-keygen -t rsa -Generating public/private rsa key pair. -Enter passphrase (empty for no passphrase): -Enter same passphrase again: -Your identification has been saved in ~/.ssh/id_rsa. -Your public key has been saved in ~/.ssh/id_rsa.pub. -The key fingerprint is: -SHA256:tBJEfyJUGTMNmPCiPg4UHywHs67MxlM2iEBAlI/W+TY fingeprint -The key's randomart image is: -+---[RSA 2048]----+ -|=*. .o++*= | -|..= +o..o. | -|.+++o + + . | -|+o*=.. + + | -|o+.=. . S | -|*.o .E . | -|o*o . . | -|.o.. | -| . | -+----[SHA256]-----+ +ssh ``` -3. Add the public key from `~/.ssh/id_rsa.pub` to services that you want to have an access from build. +For accessing repositories on GitLab.com, the `` would be +`git@gitlab.com`. -4. Try to login for the first time and accept fingerprint: -```bash -ssh Date: Fri, 4 Dec 2015 11:47:02 +0200 Subject: [PATCH 26/42] Move markdown link to the bottom [ci skip] --- doc/ci/languages/php.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/ci/languages/php.md b/doc/ci/languages/php.md index 589253cfc4..60079c090d 100644 --- a/doc/ci/languages/php.md +++ b/doc/ci/languages/php.md @@ -263,13 +263,14 @@ gitlab-runner exec shell test:app ## Example project -We have set up an [Example PHP Project](https://gitlab.com/gitlab-examples/php) -for your convenience that runs on [GitLab.com](https://gitlab.com) using our -publicly available [shared runners](../runners/README.md). +We have set up an [Example PHP Project][php-example-repo] for your convenience +that runs on [GitLab.com](https://gitlab.com) using our publicly available +[shared runners](../runners/README.md). -Want to hack it? Simply fork it, commit and push your changes. Within a few +Want to hack on it? Simply fork it, commit and push your changes. Within a few moments the changes will be picked by a public runner and the build will begin. [php-hub]: https://hub.docker.com/_/php/ [phpenv]: https://github.com/phpenv/phpenv [phpenv-installation]: https://github.com/phpenv/phpenv#installation +[php-example-repo]: https://gitlab.com/gitlab-examples/php From 4fc9e6944e363e3167fede07c0d6898ff6c7e19f Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Fri, 4 Dec 2015 11:47:50 +0200 Subject: [PATCH 27/42] Add an intro to CI services documentation [ci skip] --- doc/ci/services/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/ci/services/README.md b/doc/ci/services/README.md index 0550e9435a..0856b7679c 100644 --- a/doc/ci/services/README.md +++ b/doc/ci/services/README.md @@ -1,6 +1,9 @@ ## GitLab CI Services +GitLab CI uses the `service` keyword to define what docker containers should be +linked with your base image. Below is a list of examples you may use. + + [Using MySQL](mysql.md) + [Using PostgreSQL](postgres.md) + [Using Redis](redis.md) -+ [Using Other Services](../docker/using_docker_images.html#how-to-use-other-images-as-services) ++ [Using Other Services](../docker/using_docker_images.md#how-to-use-other-images-as-services) From 4236861df03ff86fc1b2bb8a6a0835b0f3a03244 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Mon, 7 Dec 2015 09:39:14 +0200 Subject: [PATCH 28/42] Clean up Redis CI service example [ci skip] --- doc/ci/services/redis.md | 72 ++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/doc/ci/services/redis.md b/doc/ci/services/redis.md index 523634a457..b0d04f9540 100644 --- a/doc/ci/services/redis.md +++ b/doc/ci/services/redis.md @@ -1,40 +1,68 @@ -## Using Redis +# Using Redis -It's possible to use Redis database test your apps during builds. +As many applications depend on Redis as their key-value store, you will +eventually need it in order for your tests to run. Below you are guided how to +do this with the Docker and Shell executors of GitLab Runner. -### Use Redis with Docker executor +## Use Redis with Docker executor -If you are using our Docker integration you basically have everything already. +If you are using our Docker integration you basically have everything set up +already. -1. Add this to your `.gitlab-ci.yml`: +First, in your `.gitlab-ci.yml` add: - services: - - redis +```yaml +services: + - redis:latest +``` -2. Configure your application to use the database: +Then you need to configure your application to use the Redis database, for +example: - Host: redis +```bash +Host: redis +``` -3. You can also use any other available on [DockerHub](https://hub.docker.com/_/redis/). For example: `redis:2.6`. +And that's it. Redis will now be available to be used within your testing +framework. -Example: https://gitlab.com/gitlab-examples/redis/blob/master/.gitlab-ci.yml +If you want to use any other version of Redis, check the available versions +on [Docker Hub](https://hub.docker.com/_/redis/). -### Use Redis with Shell executor +## Use Redis with Shell executor -It's possible to use Redis on manually configured servers that are using GitLab Runner with Shell executor. +Redis can also be used on manually configured servers that are using GitLab +Runner with the Shell executor. -1. First install the Redis server: +In your build machine install the Redis server: - sudo apt-get install redis-server +```bash +sudo apt-get install redis-server +``` -2. Try to connect to the server: +Verify that you can connect to the server with the `gitlab-runner` user: - # Try connecting the the Redis server - sudo -u gitlab-runner -H redis-cli +```bash +# Try connecting the the Redis server +sudo -u gitlab-runner -H redis-cli - # Quit the session - 127.0.0.1:6379> quit +# Quit the session +127.0.0.1:6379> quit +``` -4. Configure your application to use the database: +Finally, configure your application to use the database, for example: - Host: localhost +```bash +Host: localhost +``` + +## Example project + +We have set up an [Example Redis Project][redis-example-repo] for your convenience +that runs on [GitLab.com](https://gitlab.com) using our publicly available +[shared runners](../runners/README.md). + +Want to hack on it? Simply fork it, commit and push your changes. Within a few +moments the changes will be picked by a public runner and the build will begin. + +[redis-example-repo]: https://gitlab.com/gitlab-examples/redis From 149c934a1d38662358b48cdf844430de7845d1c4 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 15:59:41 +0200 Subject: [PATCH 29/42] More cleanup on Redis example --- doc/ci/services/redis.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/ci/services/redis.md b/doc/ci/services/redis.md index b0d04f9540..e6add57ca7 100644 --- a/doc/ci/services/redis.md +++ b/doc/ci/services/redis.md @@ -4,10 +4,10 @@ As many applications depend on Redis as their key-value store, you will eventually need it in order for your tests to run. Below you are guided how to do this with the Docker and Shell executors of GitLab Runner. -## Use Redis with Docker executor +## Use Redis with the Docker executor -If you are using our Docker integration you basically have everything set up -already. +If you are using GitLab's Runner Docker integration you basically have +everything set up already. First, in your `.gitlab-ci.yml` add: @@ -29,7 +29,7 @@ framework. If you want to use any other version of Redis, check the available versions on [Docker Hub](https://hub.docker.com/_/redis/). -## Use Redis with Shell executor +## Use Redis with the Shell executor Redis can also be used on manually configured servers that are using GitLab Runner with the Shell executor. From 06b86de996232b956129f2bb5dde4a7647f94f69 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 18:22:45 +0200 Subject: [PATCH 30/42] Clean up postgres CI example [ci skip] --- doc/ci/services/postgres.md | 116 ++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 45 deletions(-) diff --git a/doc/ci/services/postgres.md b/doc/ci/services/postgres.md index e57f8c5944..f82a828756 100644 --- a/doc/ci/services/postgres.md +++ b/doc/ci/services/postgres.md @@ -1,70 +1,96 @@ -## Using PostgreSQL +# Using PostgreSQL -It's possible to use PostgreSQL database test your apps during builds. +As many applications depend on PostgreSQL as their database, you will +eventually need it in order for your tests to run. Below you are guided how to +do this with the Docker and Shell executors of GitLab Runner. -### Use PostgreSQL with Docker executor +## Use PostgreSQL with the Docker executor -If you are using our Docker integration you basically have everything already. +If you are using GitLab's Runner with the Docker executor you basically have +everything set up already. -1. Add this to your `.gitlab-ci.yml`: +First, in your `.gitlab-ci.yml` add: - services: - - postgres +```yaml +services: + - postgres - variables: - # Configure postgres service (https://hub.docker.com/_/postgres/) - POSTGRES_DB: hello_world_test - POSTGRES_USER: postgres - POSTGRES_PASSWORD: "" +variables: + POSTGRES_DB: nice_marmot + POSTGRES_USER: gitlab_runner + POSTGRES_PASSWORD: "" +``` -2. Configure your application to use the database: +And then configure your application to use PostgreSQL, for example: - Host: postgres - User: postgres - Password: postgres - Database: hello_world_test +```yaml +Host: localhost +User: gitlab_runner +Password: +Database: nice_marmot +``` -3. You can also use any other available on [DockerHub](https://hub.docker.com/_/postgres/). For example: `postgres:9.3`. +You can also use any other docker image available on [Docker Hub][hub-pg]. +For example, to use PostgreSQL 9.3 the service becomes `postgres:9.3`. -Example: https://gitlab.com/gitlab-examples/postgres/blob/master/.gitlab-ci.yml +The `postgres` image can accept some environment variables. For more details +check the documentation on [Docker Hub][hub-pg]. -### Use PostgreSQL with Shell executor +## Use PostgreSQL with the Shell executor -It's possible to use PostgreSQL on manually configured servers that are using GitLab Runner with Shell executor. +You can also use PostgreSQL on manually configured servers that are using +GitLab Runner with the Shell executor. -1. First install the PostgreSQL server: +First install the PostgreSQL server: - sudo apt-get install -y postgresql postgresql-client libpq-dev +```bash +sudo apt-get install -y postgresql postgresql-client libpq-dev +``` -2. Create an user: +Then create a user: - # Install the database packages - sudo apt-get install -y postgresql postgresql-client libpq-dev +```bash +# Login to PostgreSQL +sudo -u postgres psql -d template1 - # Login to PostgreSQL - sudo -u postgres psql -d template1 +# Create a user for GitLab Runner that can create databases +# Do not type the 'template1=#', this is part of the prompt +template1=# CREATE USER gitlab_runner CREATEDB; - # Create a user for runner - # Do not type the 'template1=#', this is part of the prompt - template1=# CREATE USER runner CREATEDB; +# Create the database & grant all privileges on database +template1=# CREATE DATABASE nice_marmot OWNER gitlab_runner; - # Create the database & grant all privileges on database - template1=# CREATE DATABASE hello_world_test OWNER runner; +# Quit the database session +template1=# \q +``` - # Quit the database session - template1=# \q +Try to connect to database: -3. Try to connect to database: +```bash +# Try connecting to the new database with the new user +sudo -u gitlab_runner -H psql -d nice_marmot - # Try connecting to the new database with the new user - sudo -u gitlab-runner -H psql -d hello_world_test +# Quit the database session +nice_marmot> \q +``` - # Quit the database session - hello_world_test> \q +Finally, configure your application to use the database: -4. Configure your application to use the database: +```bash +Host: localhost +User: gitlab_runner +Password: +Database: nice_marmot +``` - Host: localhost - User: runner - Password: - Database: hello_world_test +## Example project + +We have set up an [Example PostgreSQL Project][postgres-example-repo] for your +convenience that runs on [GitLab.com](https://gitlab.com) using our publicly +available [shared runners](../runners/README.md). + +Want to hack on it? Simply fork it, commit and push your changes. Within a few +moments the changes will be picked by a public runner and the build will begin. + +[hub-pg]: https://hub.docker.com/_/postgres/ +[postgres-example-repo]: https://gitlab.com/gitlab-examples/postgres From 47e81da8c2746196ad0506d30720c775a538ebdb Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 21:11:11 +0200 Subject: [PATCH 31/42] Clean up mysql CI example --- doc/ci/services/mysql.md | 137 +++++++++++++++++++++++++-------------- 1 file changed, 90 insertions(+), 47 deletions(-) diff --git a/doc/ci/services/mysql.md b/doc/ci/services/mysql.md index 3155af6b3e..7f50b4d76c 100644 --- a/doc/ci/services/mysql.md +++ b/doc/ci/services/mysql.md @@ -1,72 +1,115 @@ -## Using MySQL +# Using MySQL -It's possible to use MySQL database test your apps during builds. +As many applications depend on MySQL as their database, you will eventually +need it in order for your tests to run. Below you are guided how to do this +with the Docker and Shell executors of GitLab Runner. -### Use MySQL with Docker executor +## Use MySQL with the Docker executor -If you are using our Docker integration you basically have everything already. +If you are using [GitLab Runner](../runners/README.md) with the Docker executor +you basically have everything set up already. -1. Add this to your `.gitlab-ci.yml`: +First, in your `.gitlab-ci.yml` add: - services: - - mysql +```yaml +services: + - mysql - variables: - # Configure mysql service (https://hub.docker.com/_/mysql/) - MYSQL_DATABASE: hello_world_test - MYSQL_ROOT_PASSWORD: mysql +variables: + # Configure mysql environment variables (https://hub.docker.com/_/mysql/) + MYSQL_DATABASE: el_duderino + MYSQL_ROOT_PASSWORD: mysql_strong_password +``` -2. Configure your application to use the database: +And then configure your application to use the database, for example: - Host: mysql - User: root - Password: mysql - Database: hello_world_test +```yaml +Host: localhost +User: root +Password: mysql_strong_password +Database: el_duderino +``` -3. You can also use any other available on [DockerHub](https://hub.docker.com/_/mysql/). For example: `mysql:5.5`. +You can also use any other docker image available on [Docker Hub][hub-mysql]. +For example, to use MySQL 5.5 the service becomes `mysql:5.5`. -Example: https://gitlab.com/gitlab-examples/mysql/blob/master/.gitlab-ci.yml +The `mysql` image can accept some environment variables. For more details +check the documentation on [Docker Hub][hub-mysql]. -### Use MySQL with Shell executor +## Use MySQL with the Shell executor -It's possible to use MySQL on manually configured servers that are using GitLab Runner with Shell executor. +You can also use MySQL on manually configured servers that are using +GitLab Runner with the Shell executor. -1. First install the MySQL server: - - sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev +First install the MySQL server: - # Pick a MySQL root password (can be anything), type it and press enter - # Retype the MySQL root password and press enter +```bash +sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev +``` -2. Create an user: +Pick a MySQL root password (can be anything), and type it twice when asked. - mysql -u root -p +*Note: As a security measure you can run `mysql_secure_installation` to +remove anonymous users, drop the test database and disable remote logins with +the root user.* - # Create a user which will be used by your apps - # do not type the 'mysql>', this is part of the prompt - # change $password in the command below to a real password you pick - mysql> CREATE USER 'runner'@'localhost' IDENTIFIED BY '$password'; +The next step is to create a user, so login to MySQL as root: - # Ensure you can use the InnoDB engine which is necessary to support long indexes - # If this fails, check your MySQL config files (e.g. `/etc/mysql/*.cnf`, `/etc/mysql/conf.d/*`) for the setting "innodb = off" - mysql> SET storage_engine=INNODB; +```bash +mysql -u root -p +``` - # Create the database - mysql> CREATE DATABASE IF NOT EXISTS `hello_world_test` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`; +Then create a user (in our case `runner`) which will be used by your +application. Change `$password` in the command below to a real strong password. - # Grant necessary permissions on the database - mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, CREATE TEMPORARY TABLES, DROP, INDEX, ALTER, LOCK TABLES ON `hello_world_test`.* TO 'runner'@'localhost'; +*Note: Do not type `mysql>`, this is part of the MySQL prompt.* - # Quit the database session - mysql> \q +```bash +mysql> CREATE USER 'runner'@'localhost' IDENTIFIED BY '$password'; +``` -3. Try to connect to database: +Create the database: - sudo -u gitlab-runner -H mysql -u runner -p -D hello_world_test +```bash +mysql> CREATE DATABASE IF NOT EXISTS `el_duderino` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`; +``` -4. Configure your application to use the database: +Grant the necessary permissions on the database: - Host: localhost - User: runner - Password: $password - Database: hello_world_test +```bash +mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, CREATE TEMPORARY TABLES, DROP, INDEX, ALTER, LOCK TABLES ON `el_duderino`.* TO 'runner'@'localhost'; +``` + +If all went well you can now quit the database session: + +```bash +mysql> \q +``` + +Now, try to connect to the newly created database to check that everything is +in place: + +```bash +mysql -u runner -p -D el_duderino +``` + +As a final step, configure your application to use the database, for example: + +```bash +Host: localhost +User: runner +Password: $password +Database: el_duderino +``` + +## Example project + +We have set up an [Example MySQL Project][mysql-example-repo] for your +convenience that runs on [GitLab.com](https://gitlab.com) using our publicly +available [shared runners](../runners/README.md). + +Want to hack on it? Simply fork it, commit and push your changes. Within a few +moments the changes will be picked by a public runner and the build will begin. + +[hub-mysql]: https://hub.docker.com/_/mysql/ +[mysql-example-repo]: https://gitlab.com/gitlab-examples/mysql From 9dc91f46df377d6220928d6292dac73bc6bae295 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 21:11:27 +0200 Subject: [PATCH 32/42] Add link to runners doc [ci skip] --- doc/ci/services/postgres.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/ci/services/postgres.md b/doc/ci/services/postgres.md index f82a828756..b8436f4f7c 100644 --- a/doc/ci/services/postgres.md +++ b/doc/ci/services/postgres.md @@ -6,8 +6,8 @@ do this with the Docker and Shell executors of GitLab Runner. ## Use PostgreSQL with the Docker executor -If you are using GitLab's Runner with the Docker executor you basically have -everything set up already. +If you are using [GitLab Runner](../runners/README.md) with the Docker executor +you basically have everything set up already. First, in your `.gitlab-ci.yml` add: @@ -21,7 +21,7 @@ variables: POSTGRES_PASSWORD: "" ``` -And then configure your application to use PostgreSQL, for example: +And then configure your application to use the database, for example: ```yaml Host: localhost From cf44dc510786775a1303384d858eb0a7bf33c34f Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 21:35:08 +0200 Subject: [PATCH 33/42] Add note about the various phpenv tools --- doc/ci/languages/php.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/ci/languages/php.md b/doc/ci/languages/php.md index 60079c090d..dacb67fa3f 100644 --- a/doc/ci/languages/php.md +++ b/doc/ci/languages/php.md @@ -179,6 +179,14 @@ Using phpenv also allows to easily configure the PHP environment with: phpenv config-add my_config.ini ``` +*__Important note:__ It seems `phpenv/phpenv` + [is abandoned](https://github.com/phpenv/phpenv/issues/57). There is a fork + at [madumlao/phpenv](https://github.com/madumlao/phpenv) that tries to bring + the project back to life. [CHH/phpenv](https://github.com/CHH/phpenv) also + seems like a good alternative. Picking any of the mentioned tools will work + with the basic phpenv commands. Guiding you to choose the right phpenv is out + of the scope of this tutorial.* + ### Install custom extensions Since this is a pretty bare installation of the PHP environment, you may need From 4ea0f06470620064c5d23e28c778f83296aeb551 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 21:35:25 +0200 Subject: [PATCH 34/42] Fix wrong naming of services keyword [ci skip] --- doc/ci/services/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/services/README.md b/doc/ci/services/README.md index 0856b7679c..1ebb0a4a25 100644 --- a/doc/ci/services/README.md +++ b/doc/ci/services/README.md @@ -1,6 +1,6 @@ ## GitLab CI Services -GitLab CI uses the `service` keyword to define what docker containers should be +GitLab CI uses the `services` keyword to define what docker containers should be linked with your base image. Below is a list of examples you may use. + [Using MySQL](mysql.md) From 0c22635aa2036ab3394c7e7bd99fd61ddd99c43c Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 21:41:56 +0200 Subject: [PATCH 35/42] More redis CI example clean up --- doc/ci/services/redis.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/ci/services/redis.md b/doc/ci/services/redis.md index e6add57ca7..b281e8f9f6 100644 --- a/doc/ci/services/redis.md +++ b/doc/ci/services/redis.md @@ -6,8 +6,8 @@ do this with the Docker and Shell executors of GitLab Runner. ## Use Redis with the Docker executor -If you are using GitLab's Runner Docker integration you basically have -everything set up already. +If you are using [GitLab Runner](../runners/README.md) with the Docker executor +you basically have everything set up already. First, in your `.gitlab-ci.yml` add: @@ -19,15 +19,15 @@ services: Then you need to configure your application to use the Redis database, for example: -```bash +```yaml Host: redis ``` And that's it. Redis will now be available to be used within your testing framework. -If you want to use any other version of Redis, check the available versions -on [Docker Hub](https://hub.docker.com/_/redis/). +You can also use any other docker image available on [Docker Hub][hub-redis]. +For example, to use Redis 2.8 the service becomes `redis:2.8`. ## Use Redis with the Shell executor @@ -52,7 +52,7 @@ sudo -u gitlab-runner -H redis-cli Finally, configure your application to use the database, for example: -```bash +```yaml Host: localhost ``` @@ -65,4 +65,5 @@ that runs on [GitLab.com](https://gitlab.com) using our publicly available Want to hack on it? Simply fork it, commit and push your changes. Within a few moments the changes will be picked by a public runner and the build will begin. +[hub-redis]: https://hub.docker.com/_/redis/ [redis-example-repo]: https://gitlab.com/gitlab-examples/redis From bbe652cdaf11dae7fa917bac1ffa4a02f2099026 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 22:26:41 +0200 Subject: [PATCH 36/42] More postgres CI service example cleanup --- doc/ci/services/postgres.md | 57 +++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/doc/ci/services/postgres.md b/doc/ci/services/postgres.md index b8436f4f7c..db5be070ee 100644 --- a/doc/ci/services/postgres.md +++ b/doc/ci/services/postgres.md @@ -13,11 +13,11 @@ First, in your `.gitlab-ci.yml` add: ```yaml services: - - postgres + - postgres:latest variables: POSTGRES_DB: nice_marmot - POSTGRES_USER: gitlab_runner + POSTGRES_USER: runner POSTGRES_PASSWORD: "" ``` @@ -25,7 +25,7 @@ And then configure your application to use the database, for example: ```yaml Host: localhost -User: gitlab_runner +User: runner Password: Database: nice_marmot ``` @@ -47,39 +47,54 @@ First install the PostgreSQL server: sudo apt-get install -y postgresql postgresql-client libpq-dev ``` -Then create a user: +The next step is to create a user, so login to PostgreSQL: ```bash -# Login to PostgreSQL sudo -u postgres psql -d template1 +``` -# Create a user for GitLab Runner that can create databases -# Do not type the 'template1=#', this is part of the prompt -template1=# CREATE USER gitlab_runner CREATEDB; +Then create a user (in our case `runner`) which will be used by your +application. Change `$password` in the command below to a real strong password. -# Create the database & grant all privileges on database -template1=# CREATE DATABASE nice_marmot OWNER gitlab_runner; +*__Note:__ Do not type `template1=#`, this is part of the PostgreSQL prompt.* -# Quit the database session +```bash +template1=# CREATE USER runner WITH PASSWORD '$password' CREATEDB; +``` + +*__Note:__ Notice that we created the user with the privilege to be able to +create databases (`CREATEDB`). In the following steps we will create a database +explicitly for that user but having that privilege can be useful if in your +testing framework you have tools that drop and create databases.* + +Create the database and grant all privileges on it for the user `runner`: + +```bash +template1=# CREATE DATABASE nice_marmot OWNER runner; +``` + +If all went well you can now quit the database session: + +```bash template1=# \q ``` -Try to connect to database: +Now, try to connect to the newly created database with the user `runner` to +check that everything is in place. ```bash -# Try connecting to the new database with the new user -sudo -u gitlab_runner -H psql -d nice_marmot - -# Quit the database session -nice_marmot> \q +psql -U runner -h localhost -d nice_marmot -W ``` -Finally, configure your application to use the database: +*__Note:__ We are explicitly telling `psql` to connect to localhost in order +to use the md5 authentication. If you omit this step you will be denied access.* -```bash +Finally, configure your application to use the database, for example: + +```yaml Host: localhost -User: gitlab_runner -Password: +User: runner +Password: $password Database: nice_marmot ``` From d55dcd11d59ebfadf49290746c5f30c2e4780c6b Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 22:27:23 +0200 Subject: [PATCH 37/42] Use the latest docker image in mysql CI example [ci skip] --- doc/ci/services/mysql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/services/mysql.md b/doc/ci/services/mysql.md index 7f50b4d76c..44bc613e6f 100644 --- a/doc/ci/services/mysql.md +++ b/doc/ci/services/mysql.md @@ -13,7 +13,7 @@ First, in your `.gitlab-ci.yml` add: ```yaml services: - - mysql + - mysql:latest variables: # Configure mysql environment variables (https://hub.docker.com/_/mysql/) From b312edaf440b729dad02749259577f6e0589c061 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 23:29:49 +0200 Subject: [PATCH 38/42] More clean up to the CI example on how to use docker images [ci skip] --- doc/ci/docker/using_docker_images.md | 100 ++++++++++----------------- 1 file changed, 36 insertions(+), 64 deletions(-) diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index 488479418b..8d4bd44053 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -1,28 +1,29 @@ # Using Docker Images -GitLab CI can use [Docker Engine](https://www.docker.com/) to build projects. +GitLab CI in conjuction with [GitLab Runner](../runners/README.md) can use +[Docker Engine](https://www.docker.com/) to test and build any application. -Docker is an open-source project that allows to use predefined images to run -applications in independent "containers" that are run within a single Linux +Docker is an open-source project that allows you to use predefined images to +run applications in independent "containers" that are run within a single Linux instance. [Docker Hub][hub] has a rich database of prebuilt images that can be used to test and build your applications. Docker, when used with GitLab CI, runs each build in a separate and isolated -container using the predefined image that is set up in `.gitlab-ci.yml`. The -container is always euphemeral which means you get only one container per build. +container using the predefined image that is set up in +[`.gitlab-ci.yml`](../yaml/README.md). This makes it easier to have a simple and reproducible build environment that can also run on your workstation. The added benefit is that you can test all the commands that we will explore later from your shell, rather than having to -test them on a CI server. +test them on a dedicated CI server. -### Register docker runner +## Register docker runner To use GitLab Runner with docker you need to register a new runner to use the `docker` executor: ```bash -gitlab-ci-multi-runner register \ +gitlab-runner register \ --url "https://gitlab.com/" \ --registration-token "PROJECT_REGISTRATION_TOKEN" \ --description "docker-ruby-2.1" \ @@ -36,7 +37,7 @@ The registered runner will use the `ruby:2.1` docker image and will run two services, `postgres:latest` and `mysql:latest`, both of which will be accessible during the build process. -### What is image +## What is image The `image` keyword is the name of the docker image that is present in the local Docker Engine (list all images with `docker images`) or any image that @@ -46,9 +47,9 @@ Hub please read the [Docker Fundamentals][] documentation. In short, with `image` we refer to the docker image, which will be used to create a container on which your build will run. -### What is service +## What is service -The `service` keyword defines just another docker image that is run during +The `services` keyword defines just another docker image that is run during your build and is linked to the docker image that the `image` keyword defines. This allows you to access the service image during build time. @@ -57,9 +58,12 @@ run a database container, eg. `mysql`. It's easier and faster to use an existing image and run it as an additional container than install `mysql` every time the project is built. -#### How is service linked to the build +You can see some widely used services examples in the relevant documentation of +[CI services examples](../services/README.md). -To better undestand how the container linking works, read +### How is service linked to the build + +To better understand how the container linking works, read [Linking containers together](https://docs.docker.com/userguide/dockerlinks/). To summarize, if you add `mysql` as service to your application, the image will @@ -69,25 +73,27 @@ The service container for MySQL will be accessible under the hostname `mysql`. So, in order to access your database service you have to connect to the host named `mysql` instead of a socket or `localhost`. -### Overwrite image and services +## Overwrite image and services -See the section below. +See [How to use other images as services](#how-to-use-other-images-as-services). -### How to use other images as services +## How to use other images as services You are not limited to have only database services. You can add as many services you need to `.gitlab-ci.yml` or manually modify `config.toml`. Any image found at [Docker Hub][hub] can be used as a service. -### Define image and services from `.gitlab-ci.yml` +## Define image and services from `.gitlab-ci.yml` You can simply define an image that will be used for all jobs and a list of services that you want to use during build time. ```yaml image: ruby:2.2 + services: - postgres:9.3 + before_script: - bundle install @@ -117,24 +123,20 @@ test:2.2: - bundle exec rake spec ``` -### Define image and services in `config.toml` +## Define image and services in `config.toml` Look for the `[runners.docker]` section: ``` -... - [runners.docker] image = "ruby:2.1" services = ["mysql:latest", "postgres:latest"] - -... ``` The image and services defined this way will be added to all builds run by that runner. -### Accessing the services +## Accessing the services Let's say that you need a Wordpress instance to test some API integration with your application. @@ -143,12 +145,8 @@ You can then use for example the [tutum/wordpress][] image in your `.gitlab-ci.yml`: ```yaml -... - services: - tutum/wordpress:latest - -... ``` When the build is run, `tutum/wordpress` will be started and you will have @@ -160,7 +158,7 @@ rules: 1. Everything after `:` is stripped 2. Backslash (`/`) is replaced with double underscores (`__`) -### Configuring services +## Configuring services Many services accept environment variables which allow you to easily change database names or set account names depending on the environment. @@ -171,46 +169,20 @@ service containers. For all possible configuration variables check the documentation of each image provided in their corresponding Docker hub page. -*Note: All variables will be passed to all service containers. It's not designed - to distinguish which variable should go where.* +*Note: All variables will be passed to all services containers. It's not +designed to distinguish which variable should go where.* -#### PostgreSQL service example +### PostgreSQL service example -To configure the database name for [postgres][postgres-hub] service, you need -to set the `POSTGRES_DB` variable: +See the specific documentation for +[using PostgreSQL as a service](../services/postgres.md). -```yaml -... +### MySQL service example -services: -- postgres +See the specific documentation for +[using MySQL as a service](../services/mysql.md). -variables: - POSTGRES_DB: gitlab - -... -``` - -For a real example visit . - -#### MySQL service example - -To use the [mysql][mysql-hub] service with an empty password during the time of -build, you need to set the `MYSQL_ALLOW_EMPTY_PASSWORD` variable: - -```yaml -... - -services: -- mysql - -variables: - MYSQL_ALLOW_EMPTY_PASSWORD: "yes" - -... -``` - -### How Docker integration works +## How Docker integration works Below is a high level overview of the steps performed by docker during build time. @@ -226,7 +198,7 @@ time. 1. Check exit status of build script. 1. Remove build container and all created service containers. -### How to debug a build locally +## How to debug a build locally *Note: The following commands are run without root privileges. You should be able to run docker with your regular user account.* From 1464a69c76cf492ad8b9674e24260e917dc7d2ef Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 8 Dec 2015 22:37:07 +0100 Subject: [PATCH 39/42] Tweak text of documentation --- .gitignore | 1 - doc/workflow/merge_when_build_succeeds.md | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 881b3fb81a..f5b6427ca0 100644 --- a/.gitignore +++ b/.gitignore @@ -38,7 +38,6 @@ public/assets/ public/uploads.* public/uploads/ shared/artifacts/ -TODO rails_best_practices_output.html /tags tmp/ diff --git a/doc/workflow/merge_when_build_succeeds.md b/doc/workflow/merge_when_build_succeeds.md index 3c055650c4..75e1fdff2b 100644 --- a/doc/workflow/merge_when_build_succeeds.md +++ b/doc/workflow/merge_when_build_succeeds.md @@ -1,12 +1,12 @@ # Merge When Build Succeeds -When reviewing a merge request that looks ready to merge but still has one or more CI builds running, you can set it to be merged automatically when the build succeeds. This way, you don't have to wait for the build to finish and remember to merge the merge request then. +When reviewing a merge request that looks ready to merge but still has one or more CI builds running, you can set it to be merged automatically when all builds succeed. This way, you don't have to wait for the builds to finish and remember to merge the request manually. ![Enable](merge_when_build_succeeds/enable.png) -When you hit the "Merge When Build Succeeds" button, the status of the Merge Request will be updated to represent the impending merge. If you cannot wait for the build to succeed and want to build immediately, this option is available in the dropdown menu on the right of the main button. +When you hit the "Merge When Build Succeeds" button, the status of the merge request will be updated to represent the impending merge. If you cannot wait for the build to succeed and want to merge immediately, this option is available in the dropdown menu on the right of the main button. -Both team developers and the author of the merge request have the option to cancel the automatic merge when they find a reason it shouldn't be merged after all. +Both team developers and the author of the merge request have the option to cancel the automatic merge if they find a reason why it shouldn't be merged after all. ![Status](merge_when_build_succeeds/status.png) From 1e7156ed701945349bef484d35c7f53f2ee4474b Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 8 Dec 2015 23:49:05 +0200 Subject: [PATCH 40/42] Use the name of the linked containers instead of localhost https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/1917#note_2833978 --- doc/ci/services/mysql.md | 5 ++++- doc/ci/services/postgres.md | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/ci/services/mysql.md b/doc/ci/services/mysql.md index 44bc613e6f..c66d77122b 100644 --- a/doc/ci/services/mysql.md +++ b/doc/ci/services/mysql.md @@ -24,12 +24,15 @@ variables: And then configure your application to use the database, for example: ```yaml -Host: localhost +Host: mysql User: root Password: mysql_strong_password Database: el_duderino ``` +If you are wondering why we used `mysql` for the `Host`, read more at +[How is service linked to the build](../docker/using_docker_images.md#how-is-service-linked-to-the-build). + You can also use any other docker image available on [Docker Hub][hub-mysql]. For example, to use MySQL 5.5 the service becomes `mysql:5.5`. diff --git a/doc/ci/services/postgres.md b/doc/ci/services/postgres.md index db5be070ee..17d21dbda1 100644 --- a/doc/ci/services/postgres.md +++ b/doc/ci/services/postgres.md @@ -24,12 +24,15 @@ variables: And then configure your application to use the database, for example: ```yaml -Host: localhost +Host: postgres User: runner Password: Database: nice_marmot ``` +If you are wondering why we used `postgres` for the `Host`, read more at +[How is service linked to the build](../docker/using_docker_images.md#how-is-service-linked-to-the-build). + You can also use any other docker image available on [Docker Hub][hub-pg]. For example, to use PostgreSQL 9.3 the service becomes `postgres:9.3`. From 28351806aa1f89f584d6905365fd34f5f0e8bbc7 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 9 Dec 2015 09:59:19 +0100 Subject: [PATCH 41/42] Give merge request widget the vars it desires --- app/controllers/projects/merge_requests_controller.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 3240c77e99..530f3d3dcb 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -7,6 +7,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits, :builds] before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds] before_action :define_show_vars, only: [:show, :diffs, :commits, :builds] + before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds] before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds] # Allow read any merge_request @@ -301,6 +302,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController end end + def define_widget_vars + @ci_commit = @merge_request.ci_commit + end + def invalid_mr # Render special view for MR with removed source or target branch render 'invalid' From 903151141da36ed9b8c2333a9b66f5c611e4efb6 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 9 Dec 2015 09:59:39 +0100 Subject: [PATCH 42/42] Tweak specs --- .../merge_requests/merge_when_build_succeeds_spec.rb | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb index ee2fb25e9e..a674124aab 100644 --- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb @@ -43,20 +43,14 @@ feature 'Merge When Build Succeeds', feature: true, js: true do context 'When it is enabled' do let(:merge_request) do - create(:merge_request_with_diffs, source_project: project, author: user, - merge_user: user, title: "MepMep", merge_when_build_succeeds: true) + create(:merge_request_with_diffs, :simple, source_project: project, author: user, + merge_user: user, title: "MepMep", merge_when_build_succeeds: true) end let!(:ci_commit) { create(:ci_commit, gl_project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) } let!(:ci_build) { create(:ci_build, commit: ci_commit) } before do - merge_request.source_project.team << [user, :master] - merge_request.source_branch = "feature" - merge_request.target_branch = "master" - merge_request.save! - - login_as user visit_merge_request(merge_request) end