Merge branch 'master' into rs-redactor-filter

This commit is contained in:
Douwe Maan 2015-10-14 22:42:59 +02:00
commit ef44138ce4
35 changed files with 402 additions and 162 deletions

View File

@ -18,6 +18,7 @@ v 8.1.0 (unreleased)
- Add first and last to pagination (Zeger-Jan van de Weg)
- Added Commit Status API
- Show CI status on commit page
- Added CI_BUILD_TAG, _STAGE, _NAME and _TRIGGERED to CI builds
- Show CI status on Your projects page and Starred projects page
- Remove "Continuous Integration" page from dashboard
- Add notes and SSL verification entries to hook APIs (Ben Boeckel)
@ -27,6 +28,7 @@ v 8.1.0 (unreleased)
- Move CI triggers page to project settings area
- Move CI project settings page to CE project settings area
- Fix bug when removed file was not appearing in merge request diff
- Show warning when build cannot be served by any of the available CI runners
- Note the original location of a moved project when notifying users of the move
- Improve error message when merging fails
- Add support of multibyte characters in LDAP UID (Roman Petrov)

View File

@ -6,7 +6,7 @@ module Ci
@runners = Ci::Runner.order('id DESC')
@runners = @runners.search(params[:search]) if params[:search].present?
@runners = @runners.page(params[:page]).per(30)
@active_runners_cnt = Ci::Runner.where("contacted_at > ?", 1.minutes.ago).count
@active_runners_cnt = Ci::Runner.online.count
end
def show
@ -66,7 +66,7 @@ module Ci
end
def runner_params
params.require(:runner).permit(:token, :description, :tag_list, :contacted_at, :active)
params.require(:runner).permit(:token, :description, :tag_list, :active)
end
end
end

View File

@ -55,7 +55,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def show
@participants = @issue.participants(current_user, @project)
@participants = @issue.participants(current_user)
@note = @project.notes.new(noteable: @issue)
@notes = @issue.notes.inc_author.fresh
@noteable = @issue

View File

@ -246,7 +246,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def define_show_vars
@participants = @merge_request.participants(current_user, @project)
@participants = @merge_request.participants(current_user)
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)

View File

@ -60,6 +60,6 @@ class Projects::RunnersController < Projects::ApplicationController
end
def runner_params
params.require(:runner).permit(:description, :tag_list, :contacted_at, :active)
params.require(:runner).permit(:description, :tag_list, :active)
end
end

View File

@ -1,20 +1,16 @@
module RunnersHelper
def runner_status_icon(runner)
unless runner.contacted_at
return content_tag :i, nil,
class: "fa fa-warning-sign",
title: "New runner. Has not connected yet"
status = runner.status
case status
when :not_connected
content_tag :i, nil,
class: "fa fa-warning",
title: "New runner. Has not connected yet"
when :online, :offline, :paused
content_tag :i, nil,
class: "fa fa-circle runner-status-#{status}",
title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago"
end
status =
if runner.active?
runner.contacted_at > 3.hour.ago ? :online : :offline
else
:paused
end
content_tag :i, nil,
class: "fa fa-circle runner-status-#{status}",
title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago"
end
end

View File

@ -119,7 +119,7 @@ module Ci
end
def variables
yaml_variables + project_variables + trigger_variables
predefined_variables + yaml_variables + project_variables + trigger_variables
end
def project
@ -231,6 +231,18 @@ module Ci
end
end
def can_be_served?(runner)
(tag_list - runner.tag_list).empty?
end
def any_runners_online?
project.any_runners? { |runner| runner.active? && runner.online? && can_be_served?(runner) }
end
def show_warning?
pending? && !any_runners_online?
end
private
def yaml_variables
@ -258,5 +270,14 @@ module Ci
[]
end
end
def predefined_variables
variables = []
variables << { key: :CI_BUILD_TAG, value: ref, public: true } if tag?
variables << { key: :CI_BUILD_NAME, value: name, public: true }
variables << { key: :CI_BUILD_STAGE, value: stage, public: true }
variables << { key: :CI_BUILD_TRIGGERED, value: 'true', public: true } if trigger_request
variables
end
end
end

View File

@ -115,12 +115,12 @@ module Ci
web_url
end
def any_runners?
if runners.active.any?
def any_runners?(&block)
if runners.active.any?(&block)
return true
end
shared_runners_enabled && Ci::Runner.shared.active.any?
shared_runners_enabled && Ci::Runner.shared.active.any?(&block)
end
def set_default_values

View File

@ -20,6 +20,8 @@
module Ci
class Runner < ActiveRecord::Base
extend Ci::Model
LAST_CONTACT_TIME = 5.minutes.ago
has_many :builds, class_name: 'Ci::Build'
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
@ -33,6 +35,7 @@ module Ci
scope :shared, ->() { where(is_shared: true) }
scope :active, ->() { where(active: true) }
scope :paused, ->() { where(active: false) }
scope :online, ->() { where('contacted_at > ?', LAST_CONTACT_TIME) }
acts_as_taggable
@ -65,6 +68,20 @@ module Ci
is_shared
end
def online?
contacted_at && contacted_at > LAST_CONTACT_TIME
end
def status
if contacted_at.nil?
:not_connected
elsif active?
online? ? :online : :offline
else
:paused
end
end
def belongs_to_one_project?
runner_projects.count == 1
end

View File

@ -88,4 +88,8 @@ class CommitStatus < ActiveRecord::Base
def retry_url
nil
end
def show_warning?
false
end
end

View File

@ -43,67 +43,57 @@ module Mentionable
self
end
# Determine whether or not a cross-reference Note has already been created between this Mentionable and
# the specified target.
def has_mentioned?(target)
SystemNoteService.cross_reference_exists?(target, local_reference)
end
def mentioned_users(current_user = nil, load_lazy_references: true)
# TODO: Douwe: Will be simplified when the "Simplify ..." MR is merged.
def all_references(current_user = self.author, text = nil, load_lazy_references: true)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user, load_lazy_references: load_lazy_references)
self.class.mentionable_attrs.each do |attr, options|
text = send(attr)
cache_key = [self, attr] if options[:cache]
ext.analyze(text, cache_key: cache_key, pipeline: options[:pipeline])
end
ext.users
end
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
def references(p = project, current_user = self.author, text = nil, load_lazy_references: true)
return [] if text.blank?
ext = Gitlab::ReferenceExtractor.new(p, current_user, load_lazy_references: load_lazy_references)
if text
ext.analyze(text)
else
self.class.mentionable_attrs.each do |attr, options|
text = send(attr)
cache_key = [self, attr] if options[:cache]
ext.analyze(text, cache_key: cache_key)
options[:cache_key] = [self, attr] if options.delete(:cache)
ext.analyze(text, options)
end
end
(ext.issues + ext.merge_requests + ext.commits) - [local_reference]
ext
end
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
def create_cross_references!(p = project, a = author, without = [])
refs = references(p)
def mentioned_users(current_user = nil, load_lazy_references: true)
all_references(current_user).users
end
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
def referenced_mentionables(current_user = self.author, text = nil)
refs = all_references(current_user, text)
(refs.issues + refs.merge_requests + refs.commits) - [local_reference]
end
# Create a cross-reference Note for each GFM reference to another Mentionable found in the +mentionable_attrs+.
def create_cross_references!(author = self.author, without = [], text = nil)
refs = referenced_mentionables(author, text)
# We're using this method instead of Array diffing because that requires
# both of the object's `hash` values to be the same, which may not be the
# case for otherwise identical Commit objects.
refs.reject! { |ref| without.include?(ref) }
refs.reject! { |ref| without.include?(ref) || cross_reference_exists?(ref) }
refs.each do |ref|
SystemNoteService.cross_reference(ref, local_reference, a)
SystemNoteService.cross_reference(ref, local_reference, author)
end
end
# When a mentionable field is changed, creates cross-reference notes that
# don't already exist
def create_new_cross_references!(p = project, a = author)
def create_new_cross_references!(author = self.author)
changes = detect_mentionable_changes
return if changes.empty?
original_text = changes.collect { |_, vals| vals.first }.join(' ')
preexisting = references(p, self.author, original_text)
create_cross_references!(p, a, preexisting)
preexisting = referenced_mentionables(author, original_text)
create_cross_references!(author, preexisting)
end
private
@ -125,4 +115,10 @@ module Mentionable
# Only include changed fields that are mentionable
source.select { |key, val| mentionable.include?(key) }
end
# Determine whether or not a cross-reference Note has already been created between this Mentionable and
# the specified target.
def cross_reference_exists?(target)
SystemNoteService.cross_reference_exists?(target, local_reference)
end
end

View File

@ -37,7 +37,8 @@ module Participable
# Be aware that this method makes a lot of sql queries.
# Save result into variable if you are going to reuse it inside same request
def participants(current_user = self.author, project = self.project, load_lazy_references: true)
<<<<<<< HEAD
def participants(current_user = self.author, load_lazy_references: true)
participants = self.class.participant_attrs.flat_map do |attr|
value =
if attr.respond_to?(:call)
@ -46,16 +47,14 @@ module Participable
send(attr)
end
participants_for(value, current_user, project)
participants_for(value, current_user)
end.compact.uniq
if load_lazy_references
participants = Gitlab::Markdown::ReferenceFilter::LazyReference.load(participants).uniq
if project
participants.select! do |user|
user.can?(:read_project, project)
end
participants.select! do |user|
user.can?(:read_project, project)
end
end
@ -64,14 +63,14 @@ module Participable
private
def participants_for(value, current_user = nil, project = nil)
def participants_for(value, current_user = nil)
case value
when User, Gitlab::Markdown::ReferenceFilter::LazyReference
[value]
when Enumerable, ActiveRecord::Relation
value.flat_map { |v| participants_for(v, current_user, project) }
value.flat_map { |v| participants_for(v, current_user) }
when Participable
value.participants(current_user, project, load_lazy_references: false)
value.participants(current_user, load_lazy_references: false)
end
end
end

View File

@ -62,7 +62,6 @@ class Note < ActiveRecord::Base
serialize :st_diff
before_create :set_diff, if: ->(n) { n.line_code.present? }
after_update :set_references
class << self
def discussions_from_notes(notes)
@ -333,15 +332,13 @@ class Note < ActiveRecord::Base
end
def noteable_type_name
if noteable_type.present?
noteable_type.downcase
end
noteable_type.downcase if noteable_type.present?
end
# FIXME: Hack for polymorphic associations with STI
# For more information visit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations
def noteable_type=(sType)
super(sType.to_s.classify.constantize.base_class.to_s)
def noteable_type=(noteable_type)
super(noteable_type.to_s.classify.constantize.base_class.to_s)
end
# Reset notes events cache
@ -357,10 +354,6 @@ class Note < ActiveRecord::Base
Event.reset_event_cache_for(self)
end
def set_references
create_new_cross_references!(project, author)
end
def system?
read_attribute(:system)
end

View File

@ -17,7 +17,7 @@ module Ci
builds = builds.order('created_at ASC')
build = builds.find do |build|
(build.tag_list - current_runner.tag_list).empty?
build.can_be_served?(current_runner)
end

View File

@ -74,48 +74,30 @@ class GitPushService
def process_commit_messages(ref)
is_default_branch = is_default_branch?(ref)
authors = Hash.new do |hash, commit|
email = commit.author_email
return hash[email] if hash.has_key?(email)
hash[email] = commit_user(commit)
end
@push_commits.each do |commit|
# Close issues if these commits were pushed to the project's default branch and the commit message matches the
# closing regex. Exclude any mentioned Issues from cross-referencing even if the commits are being pushed to
# a different branch.
issues_to_close = commit.closes_issues(user)
# Load commit author only if needed.
# For push with 1k commits it prevents 900+ requests in database
author = nil
# Keep track of the issues that will be actually closed because they are on a default branch.
# Hence, when creating cross-reference notes, the not-closed issues (on non-default branches)
# will also have cross-reference.
actually_closed_issues = []
closed_issues = []
if issues_to_close.present? && is_default_branch
author ||= commit_user(commit)
actually_closed_issues = issues_to_close
issues_to_close.each do |issue|
Issues::CloseService.new(project, author, {}).execute(issue, commit)
if is_default_branch
# Close issues if these commits were pushed to the project's default branch and the commit message matches the
# closing regex. Exclude any mentioned Issues from cross-referencing even if the commits are being pushed to
# a different branch.
closed_issues = commit.closes_issues(user)
closed_issues.each do |issue|
Issues::CloseService.new(project, authors[commit], {}).execute(issue, commit)
end
end
if project.default_issues_tracker?
create_cross_reference_notes(commit, actually_closed_issues)
end
end
end
def create_cross_reference_notes(commit, issues_to_close)
# Create cross-reference notes for any other references than those given in issues_to_close.
# Omit any issues that were referenced in an issue-closing phrase, or have already been
# mentioned from this commit (probably from this commit being pushed to a different branch).
refs = commit.references(project, user) - issues_to_close
refs.reject! { |r| commit.has_mentioned?(r) }
if refs.present?
author ||= commit_user(commit)
refs.each do |r|
SystemNoteService.cross_reference(r, commit, author)
end
commit.create_cross_references!(authors[commit], closed_issues)
end
end

View File

@ -10,7 +10,7 @@ module Issues
issue.update_attributes(label_ids: label_params)
notification_service.new_issue(issue, current_user)
event_service.open_issue(issue, current_user)
issue.create_cross_references!(issue.project, current_user)
issue.create_cross_references!(current_user)
execute_hooks(issue, 'open')
end

View File

@ -35,7 +35,7 @@ module Issues
create_title_change_note(issue, issue.previous_changes['title'].first)
end
issue.create_new_cross_references!(issue.project, current_user)
issue.create_new_cross_references!
execute_hooks(issue, 'update')
end

View File

@ -18,7 +18,7 @@ module MergeRequests
merge_request.update_attributes(label_ids: label_params)
event_service.open_mr(merge_request, current_user)
notification_service.new_merge_request(merge_request, current_user)
merge_request.create_cross_references!(merge_request.project, current_user)
merge_request.create_cross_references!(current_user)
execute_hooks(merge_request)
end

View File

@ -59,7 +59,7 @@ module MergeRequests
merge_request.mark_as_unchecked
end
merge_request.create_new_cross_references!(merge_request.project, current_user)
merge_request.create_new_cross_references!
execute_hooks(merge_request, 'update')
end

View File

@ -11,13 +11,7 @@ module Notes
# Skip system notes, like status changes and cross-references.
unless note.system
event_service.leave_note(note, note.author)
# Create a cross-reference note if this Note contains GFM that names an
# issue, merge request, or commit.
note.references.each do |mentioned|
SystemNoteService.cross_reference(mentioned, note.noteable, note.author)
end
note.create_cross_references!
execute_hooks(note)
end
end

View File

@ -4,7 +4,7 @@ module Notes
return note unless note.editable?
note.update_attributes(params.merge(updated_by: current_user))
note.create_new_cross_references!
note.reset_events_cache
note

View File

@ -25,7 +25,7 @@
%a
Build ##{@build.id}
&middot;
%i.fa.fa-warning-sign
%i.fa.fa-warning
This build was retried.
.gray-content-block.second-block
@ -39,6 +39,27 @@
.pull-right
= @build.updated_at.stamp('19:00 Aug 27')
- if @build.show_warning?
- unless @build.any_runners_online?
.bs-callout.bs-callout-warning
%p
- if no_runners_for_project?(@build.project)
This build is stuck, because the project doesn't have runners assigned.
- elsif @build.tags.any?
This build is stuck.
%br
This build is stuck, because you don't have any active runners online with these tags assigned to the project:
- @build.tags.each do |tag|
%span.label.label-primary
= tag
- else
This build is stuck, because you don't have any active runners online that can run this build.
%br
Go to
= link_to namespace_project_runners_path(@build.gl_project.namespace, @build.gl_project) do
Runners page
.row.prepend-top-default
.col-md-9
.clearfix

View File

@ -9,6 +9,9 @@
- else
%strong Build ##{commit_status.id}
- if commit_status.show_warning?
%i.fa.fa-warning.text-warning
%td
= commit_status.ref

View File

@ -15,21 +15,27 @@ The API_TOKEN will take the Secure Variable value: `SECURE`.
### Predefined variables (Environment Variables)
| Variable | Description |
| Variable | Runner | Description |
|-------------------------|-------------|
| **CI** | Mark that build is executed in CI environment |
| **GITLAB_CI** | Mark that build is executed in GitLab CI environment |
| **CI_SERVER** | Mark that build is executed in CI environment |
| **CI_SERVER_NAME** | CI server that is used to coordinate builds |
| **CI_SERVER_VERSION** | Not yet defined |
| **CI_SERVER_REVISION** | Not yet defined |
| **CI_BUILD_REF** | The commit revision for which project is built |
| **CI_BUILD_BEFORE_SHA** | The first commit that were included in push request |
| **CI_BUILD_REF_NAME** | The branch or tag name for which project is built |
| **CI_BUILD_ID** | The unique id of the current build that GitLab CI uses internally |
| **CI_BUILD_REPO** | The URL to clone the Git repository |
| **CI_PROJECT_ID** | The unique id of the current project that GitLab CI uses internally |
| **CI_PROJECT_DIR** | The full path where the repository is cloned and where the build is ran |
| **CI** | 0.4 | Mark that build is executed in CI environment |
| **GITLAB_CI** | all | Mark that build is executed in GitLab CI environment |
| **CI_SERVER** | all | Mark that build is executed in CI environment |
| **CI_SERVER_NAME** | all | CI server that is used to coordinate builds |
| **CI_SERVER_VERSION** | all | Not yet defined |
| **CI_SERVER_REVISION** | all | Not yet defined |
| **CI_BUILD_REF** | all | The commit revision for which project is built |
| **CI_BUILD_TAG** | 0.5 | The commit tag name. Present only when building tags. |
| **CI_BUILD_NAME** | 0.5 | The name of the build as defined in `.gitlab-ci.yml` |
| **CI_BUILD_STAGE** | 0.5 | The name of the stage as defined in `.gitlab-ci.yml` |
| **CI_BUILD_BEFORE_SHA** | all | The first commit that were included in push request |
| **CI_BUILD_REF_NAME** | all | The branch or tag name for which project is built |
| **CI_BUILD_ID** | all | The unique id of the current build that GitLab CI uses internally |
| **CI_BUILD_REPO** | all | The URL to clone the Git repository |
| **CI_BUILD_TRIGGERED** | 0.5 | The flag to indicate that build was triggered |
| **CI_PROJECT_ID** | all | The unique id of the current project that GitLab CI uses internally |
| **CI_PROJECT_DIR** | all | The full path where the repository is cloned and where the build is ran |
**Some of the variables are only available when using runner with at least defined version.**
Example values:
@ -39,6 +45,10 @@ export CI_BUILD_ID="50"
export CI_BUILD_REF="1ecfd275763eff1d6b4844ea3168962458c9f27a"
export CI_BUILD_REF_NAME="master"
export CI_BUILD_REPO="https://gitlab.com/gitlab-org/gitlab-ce.git"
export CI_BUILD_TAG="1.0.0"
export CI_BUILD_NAME="spec:other"
export CI_BUILD_STAGE="test"
export CI_BUILD_TRIGGERED="true"
export CI_PROJECT_DIR="/builds/gitlab-org/gitlab-ce"
export CI_PROJECT_ID="34"
export CI_SERVER="yes"

View File

@ -12,7 +12,7 @@ describe RunnersHelper do
end
it "returns online text" do
runner = FactoryGirl.build(:ci_runner, contacted_at: 1.hour.ago, active: true)
runner = FactoryGirl.build(:ci_runner, contacted_at: 1.second.ago, active: true)
expect(runner_status_icon(runner)).to include("Runner is online")
end
end

View File

@ -200,13 +200,34 @@ describe Ci::Build do
context 'returns variables' do
subject { build.variables }
let(:variables) do
let(:predefined_variables) do
[
{ key: :CI_BUILD_NAME, value: 'test', public: true },
{ key: :CI_BUILD_STAGE, value: 'stage', public: true },
]
end
let(:yaml_variables) do
[
{ key: :DB_NAME, value: 'postgres', public: true }
]
end
it { is_expected.to eq(variables) }
before { build.update_attributes(stage: 'stage') }
it { is_expected.to eq(predefined_variables + yaml_variables) }
context 'for tag' do
let(:tag_variable) do
[
{ key: :CI_BUILD_TAG, value: 'master', public: true }
]
end
before { build.update_attributes(tag: true) }
it { is_expected.to eq(tag_variable + predefined_variables + yaml_variables) }
end
context 'and secure variables' do
let(:secure_variables) do
@ -219,7 +240,7 @@ describe Ci::Build do
build.project.variables << Ci::Variable.new(key: 'SECRET_KEY', value: 'secret_value')
end
it { is_expected.to eq(variables + secure_variables) }
it { is_expected.to eq(predefined_variables + yaml_variables + secure_variables) }
context 'and trigger variables' do
let(:trigger) { FactoryGirl.create :ci_trigger, project: project }
@ -229,12 +250,17 @@ describe Ci::Build do
{ key: :TRIGGER_KEY, value: 'TRIGGER_VALUE', public: false }
]
end
let(:predefined_trigger_variable) do
[
{ key: :CI_BUILD_TRIGGERED, value: 'true', public: true }
]
end
before do
build.trigger_request = trigger_request
end
it { is_expected.to eq(variables + secure_variables + trigger_variables) }
it { is_expected.to eq(predefined_variables + predefined_trigger_variable + yaml_variables + secure_variables + trigger_variables) }
end
end
end
@ -273,4 +299,105 @@ describe Ci::Build do
is_expected.to eq(['rec1', pusher_email])
end
end
describe :can_be_served? do
let(:runner) { FactoryGirl.create :ci_specific_runner }
before { build.project.runners << runner }
context 'runner without tags' do
it 'can handle builds without tags' do
expect(build.can_be_served?(runner)).to be_truthy
end
it 'cannot handle build with tags' do
build.tag_list = ['aa']
expect(build.can_be_served?(runner)).to be_falsey
end
end
context 'runner with tags' do
before { runner.tag_list = ['bb', 'cc'] }
it 'can handle builds without tags' do
expect(build.can_be_served?(runner)).to be_truthy
end
it 'can handle build with matching tags' do
build.tag_list = ['bb']
expect(build.can_be_served?(runner)).to be_truthy
end
it 'cannot handle build with not matching tags' do
build.tag_list = ['aa']
expect(build.can_be_served?(runner)).to be_falsey
end
end
end
describe :any_runners_online? do
subject { build.any_runners_online? }
context 'when no runners' do
it { is_expected.to be_falsey }
end
context 'if there are runner' do
let(:runner) { FactoryGirl.create :ci_specific_runner }
before do
build.project.runners << runner
runner.update_attributes(contacted_at: 1.second.ago)
end
it { is_expected.to be_truthy }
it 'that is inactive' do
runner.update_attributes(active: false)
is_expected.to be_falsey
end
it 'that is not online' do
runner.update_attributes(contacted_at: nil)
is_expected.to be_falsey
end
it 'that cannot handle build' do
expect_any_instance_of(Ci::Build).to receive(:can_be_served?).and_return(false)
is_expected.to be_falsey
end
end
end
describe :show_warning? do
subject { build.show_warning? }
%w(pending).each do |state|
context "if commit_status.status is #{state}" do
before { build.status = state }
it { is_expected.to be_truthy }
context "and there are specific runner" do
let(:runner) { FactoryGirl.create :ci_specific_runner, contacted_at: 1.second.ago }
before do
build.project.runners << runner
runner.save
end
it { is_expected.to be_falsey }
end
end
end
%w(success failed canceled running).each do |state|
context "if commit_status.status is #{state}" do
before { build.status = state }
it { is_expected.to be_falsey }
end
end
end
end

View File

@ -259,5 +259,18 @@ describe Ci::Project do
FactoryGirl.create(:ci_shared_runner)
expect(project.any_runners?).to be_falsey
end
it "checks the presence of specific runner" do
project = FactoryGirl.create(:ci_project)
specific_runner = FactoryGirl.create(:ci_specific_runner)
project.runners << specific_runner
expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
end
it "checks the presence of shared runner" do
project = FactoryGirl.create(:ci_project, shared_runners_enabled: true)
shared_runner = FactoryGirl.create(:ci_shared_runner)
expect(project.any_runners? { |runner| runner == shared_runner }).to be_truthy
end
end
end

View File

@ -48,6 +48,71 @@ describe Ci::Runner do
it { expect(shared_runner.only_for?(project)).to be_truthy }
end
describe :online do
subject { Ci::Runner.online }
before do
@runner1 = FactoryGirl.create(:ci_shared_runner, contacted_at: 1.year.ago)
@runner2 = FactoryGirl.create(:ci_shared_runner, contacted_at: 1.second.ago)
end
it { is_expected.to eq([@runner2])}
end
describe :online? do
let(:runner) { FactoryGirl.create(:ci_shared_runner) }
subject { runner.online? }
context 'never contacted' do
before { runner.contacted_at = nil }
it { is_expected.to be_falsey }
end
context 'contacted long time ago time' do
before { runner.contacted_at = 1.year.ago }
it { is_expected.to be_falsey }
end
context 'contacted 1s ago' do
before { runner.contacted_at = 1.second.ago }
it { is_expected.to be_truthy }
end
end
describe :status do
let(:runner) { FactoryGirl.create(:ci_shared_runner, contacted_at: 1.second.ago) }
subject { runner.status }
context 'never connected' do
before { runner.contacted_at = nil }
it { is_expected.to eq(:not_connected) }
end
context 'contacted 1s ago' do
before { runner.contacted_at = 1.second.ago }
it { is_expected.to eq(:online) }
end
context 'contacted long time ago' do
before { runner.contacted_at = 1.year.ago }
it { is_expected.to eq(:offline) }
end
context 'inactive' do
before { runner.active = false }
it { is_expected.to eq(:paused) }
end
end
describe "belongs_to_one_project?" do
it "returns false if there are two projects runner assigned to" do
runner = FactoryGirl.create(:ci_specific_runner)

View File

@ -89,9 +89,9 @@ eos
end
it_behaves_like 'a mentionable' do
subject { commit }
subject { create(:project).commit }
let(:author) { create(:user, email: commit.author_email) }
let(:author) { create(:user, email: subject.author_email) }
let(:backref_text) { "commit #{subject.id}" }
let(:set_mentionable_text) do
->(txt) { allow(subject).to receive(:safe_message).and_return(txt) }

View File

@ -25,7 +25,7 @@ describe Issue, "Mentionable" do
it 'correctly removes already-mentioned Commits' do
expect(SystemNoteService).not_to receive(:cross_reference)
issue.create_cross_references!(project, author, [commit2])
issue.create_cross_references!(author, [commit2])
end
end

View File

@ -69,7 +69,7 @@ describe Issue do
end
it_behaves_like 'an editable mentionable' do
subject { create(:issue, project: project) }
subject { create(:issue) }
let(:backref_text) { "issue #{subject.to_reference}" }
let(:set_mentionable_text) { ->(txt){ subject.description = txt } }

View File

@ -192,10 +192,9 @@ describe Note do
end
it_behaves_like 'an editable mentionable' do
subject { create :note, noteable: issue, project: project }
subject { create :note, noteable: issue, project: issue.project }
let(:project) { create(:project) }
let(:issue) { create :issue, project: project }
let(:issue) { create :issue }
let(:backref_text) { issue.gfm_reference }
let(:set_mentionable_text) { ->(txt) { subject.note = txt } }
end

View File

@ -76,6 +76,8 @@ describe Ci::API::API do
expect(response.status).to eq(201)
expect(json_response["variables"]).to eq([
{ "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
{ "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
{ "key" => "DB_NAME", "value" => "postgres", "public" => true },
{ "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
])
@ -93,6 +95,9 @@ describe Ci::API::API do
expect(response.status).to eq(201)
expect(json_response["variables"]).to eq([
{ "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
{ "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
{ "key" => "CI_BUILD_TRIGGERED", "value" => "true", "public" => true },
{ "key" => "DB_NAME", "value" => "postgres", "public" => true },
{ "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
{ "key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false },

View File

@ -155,7 +155,7 @@ describe GitPushService do
before do
allow(commit).to receive_messages(
safe_message: "this commit \n mentions ##{issue.id}",
safe_message: "this commit \n mentions #{issue.to_reference}",
references: [issue],
author_name: commit_author.name,
author_email: commit_author.email

View File

@ -5,7 +5,7 @@
# - let(:set_mentionable_text) { lambda { |txt| "block that assigns txt to the subject's mentionable_text" } }
def common_mentionable_setup
let(:project) { create :project }
let(:project) { subject.project }
let(:author) { subject.author }
let(:mentioned_issue) { create(:issue, project: project) }
@ -67,7 +67,7 @@ shared_examples 'a mentionable' do
it "extracts references from its reference property" do
# De-duplicate and omit itself
refs = subject.references(project)
refs = subject.referenced_mentionables
expect(refs.size).to eq(6)
expect(refs).to include(mentioned_issue)
expect(refs).to include(mentioned_mr)
@ -86,14 +86,7 @@ shared_examples 'a mentionable' do
with(referenced, subject.local_reference, author)
end
subject.create_cross_references!(project, author)
end
it 'detects existing cross-references' do
SystemNoteService.cross_reference(mentioned_issue, subject.local_reference, author)
expect(subject).to have_mentioned(mentioned_issue)
expect(subject).not_to have_mentioned(mentioned_mr)
subject.create_cross_references!
end
end
@ -145,6 +138,6 @@ shared_examples 'an editable mentionable' do
end
set_mentionable_text.call(new_text)
subject.create_new_cross_references!(project, author)
subject.create_new_cross_references!(author)
end
end