summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/diffs/store/actions.js2
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js12
-rw-r--r--app/assets/stylesheets/framework/variables_overrides.scss1
-rw-r--r--app/controllers/boards/issues_controller.rb16
-rw-r--r--app/controllers/projects/branches_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb7
-rw-r--r--app/controllers/projects/pipelines_controller.rb10
-rw-r--r--app/controllers/projects/tags_controller.rb2
-rw-r--r--app/finders/pipelines_finder.rb2
-rw-r--r--app/helpers/sorting_helper.rb12
-rw-r--r--app/models/ci/pipeline.rb31
-rw-r--r--app/models/ci/pipeline_enums.rb3
-rw-r--r--app/models/ci/runner.rb3
-rw-r--r--app/models/clusters/kubernetes_namespace.rb4
-rw-r--r--app/models/clusters/platforms/kubernetes.rb4
-rw-r--r--app/models/commit.rb4
-rw-r--r--app/models/commit_collection.rb2
-rw-r--r--app/models/concerns/chronic_duration_attribute.rb2
-rw-r--r--app/models/hooks/web_hook.rb4
-rw-r--r--app/models/issue.rb14
-rw-r--r--app/models/merge_request.rb16
-rw-r--r--app/models/project.rb28
-rw-r--r--app/models/project_services/kubernetes_service.rb4
-rw-r--r--app/models/project_services/pipelines_email_service.rb4
-rw-r--r--app/serializers/README.md4
-rw-r--r--app/serializers/issue_board_entity.rb50
-rw-r--r--app/serializers/issue_serializer.rb6
-rw-r--r--app/serializers/label_entity.rb4
-rw-r--r--app/serializers/pipeline_entity.rb1
-rw-r--r--app/services/ci/create_pipeline_service.rb5
-rw-r--r--app/services/merge_requests/base_service.rb18
-rw-r--r--app/services/merge_requests/create_service.rb7
-rw-r--r--app/services/merge_requests/refresh_service.rb1
-rw-r--r--app/services/projects/auto_devops/disable_service.rb2
-rw-r--r--app/services/test_hooks/project_service.rb2
-rw-r--r--app/validators/duration_validator.rb6
-rw-r--r--app/views/admin/users/index.html.haml24
-rw-r--r--app/views/projects/settings/ci_cd/_form.html.haml2
-rw-r--r--app/views/shared/runners/_form.html.haml2
-rw-r--r--app/workers/update_head_pipeline_for_merge_request_worker.rb6
40 files changed, 218 insertions, 111 deletions
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 8b477c678fd..c87e178c8cf 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -148,7 +148,7 @@ export const scrollToLineIfNeededParallel = (_, line) => {
};
export const loadCollapsedDiff = ({ commit }, file) =>
- axios.get(file.loadCollapsedDiffUrl).then(res => {
+ axios.get(file.load_collapsed_diff_url).then(res => {
commit(types.ADD_COLLAPSED_DIFFS, {
file,
data: res.data,
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index f0895661bf2..331fb052371 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -130,7 +130,7 @@ export default {
if (file.highlighted_diff_lines) {
file.highlighted_diff_lines = file.highlighted_diff_lines.map(line => {
- if (lineCheck(line)) {
+ if (!line.discussions.some(({ id }) => discussion.id === id) && lineCheck(line)) {
return {
...line,
discussions: line.discussions.concat(discussion),
@@ -150,11 +150,17 @@ export default {
return {
left: {
...line.left,
- discussions: left ? line.left.discussions.concat(discussion) : [],
+ discussions:
+ left && !line.left.discussions.some(({ id }) => id === discussion.id)
+ ? line.left.discussions.concat(discussion)
+ : (line.left && line.left.discussions) || [],
},
right: {
...line.right,
- discussions: right && !left ? line.right.discussions.concat(discussion) : [],
+ discussions:
+ right && !left && !line.right.discussions.some(({ id }) => id === discussion.id)
+ ? line.right.discussions.concat(discussion)
+ : (line.right && line.right.discussions) || [],
},
};
}
diff --git a/app/assets/stylesheets/framework/variables_overrides.scss b/app/assets/stylesheets/framework/variables_overrides.scss
index 759b4f333ca..711de02cd39 100644
--- a/app/assets/stylesheets/framework/variables_overrides.scss
+++ b/app/assets/stylesheets/framework/variables_overrides.scss
@@ -19,3 +19,4 @@ $info: $blue-500;
$warning: $orange-500;
$danger: $red-500;
$zindex-modal-backdrop: 1040;
+$nav-divider-margin-y: ($grid-size / 2);
diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb
index 7f874687212..0dd7500623d 100644
--- a/app/controllers/boards/issues_controller.rb
+++ b/app/controllers/boards/issues_controller.rb
@@ -100,18 +100,12 @@ module Boards
.merge(board_id: params[:board_id], list_id: params[:list_id], request: request)
end
+ def serializer
+ IssueSerializer.new(current_user: current_user)
+ end
+
def serialize_as_json(resource)
- resource.as_json(
- only: [:id, :iid, :project_id, :title, :confidential, :due_date, :relative_position, :weight],
- labels: true,
- issue_endpoints: true,
- include_full_project_path: board.group_board?,
- include: {
- project: { only: [:id, :path] },
- assignees: { only: [:id, :name, :username], methods: [:avatar_url] },
- milestone: { only: [:id, :title] }
- }
- )
+ serializer.represent(resource, serializer: 'board', include_full_project_path: board.group_board?)
end
def whitelist_query_limiting
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 95a014d24da..a6bfb913900 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -22,7 +22,7 @@ class Projects::BranchesController < Projects::ApplicationController
# Fetch branches for the specified mode
fetch_branches_by_mode
- @refs_pipelines = @project.pipelines.latest_successful_for_refs(@branches.map(&:name))
+ @refs_pipelines = @project.ci_pipelines.latest_successful_for_refs(@branches.map(&:name))
@merged_branch_names = repository.merged_branch_names(@branches.map(&:name))
# n+1: https://gitlab.com/gitlab-org/gitaly/issues/992
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index b3d77335c2a..ddffbb17ace 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -22,12 +22,9 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
def render_diffs
@environment = @merge_request.environments_for(current_user).last
- notes_grouped_by_path = renderable_notes.group_by { |note| note.position.file_path }
- @diffs.diff_files.each do |diff_file|
- notes = notes_grouped_by_path.fetch(diff_file.file_path, [])
- notes.each { |note| diff_file.unfold_diff_lines(note.position) }
- end
+ note_positions = renderable_notes.map(&:position).compact
+ @diffs.unfold_diff_files(note_positions)
@diffs.write_cache
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 53b29d4146e..67827b1d3bb 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -46,7 +46,7 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def new
- @pipeline = project.pipelines.new(ref: @project.default_branch)
+ @pipeline = project.all_pipelines.new(ref: @project.default_branch)
end
def create
@@ -142,9 +142,9 @@ class Projects::PipelinesController < Projects::ApplicationController
@charts[:pipeline_times] = Gitlab::Ci::Charts::PipelineTime.new(project)
@counts = {}
- @counts[:total] = @project.pipelines.count(:all)
- @counts[:success] = @project.pipelines.success.count(:all)
- @counts[:failed] = @project.pipelines.failed.count(:all)
+ @counts[:total] = @project.all_pipelines.count(:all)
+ @counts[:success] = @project.all_pipelines.success.count(:all)
+ @counts[:failed] = @project.all_pipelines.failed.count(:all)
end
private
@@ -164,7 +164,7 @@ class Projects::PipelinesController < Projects::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def pipeline
@pipeline ||= project
- .pipelines
+ .all_pipelines
.includes(user: :status)
.find_by!(id: params[:id])
.present(current_user: current_user)
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 2b28670a49b..686d66b10a3 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -20,7 +20,7 @@ class Projects::TagsController < Projects::ApplicationController
@tags = Kaminari.paginate_array(@tags).page(params[:page])
tag_names = @tags.map(&:name)
- @tags_pipelines = @project.pipelines.latest_successful_for_refs(tag_names)
+ @tags_pipelines = @project.ci_pipelines.latest_successful_for_refs(tag_names)
@releases = project.releases.where(tag: tag_names)
respond_to do |format|
diff --git a/app/finders/pipelines_finder.rb b/app/finders/pipelines_finder.rb
index 35d0e1acce5..f5aadc42ff0 100644
--- a/app/finders/pipelines_finder.rb
+++ b/app/finders/pipelines_finder.rb
@@ -8,7 +8,7 @@ class PipelinesFinder
def initialize(project, current_user, params = {})
@project = project
@current_user = current_user
- @pipelines = project.pipelines
+ @pipelines = project.all_pipelines
@params = params
end
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 8ed2a2ec9f4..74113aee89d 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -120,6 +120,18 @@ module SortingHelper
}
end
+ def users_sort_options_hash
+ {
+ sort_value_name => sort_title_name,
+ sort_value_recently_signin => sort_title_recently_signin,
+ sort_value_oldest_signin => sort_title_oldest_signin,
+ sort_value_recently_created => sort_title_recently_created,
+ sort_value_oldest_created => sort_title_oldest_created,
+ sort_value_recently_updated => sort_title_recently_updated,
+ sort_value_oldest_updated => sort_title_oldest_updated
+ }
+ end
+
def sortable_item(item, path, sorted_by)
link_to item, path, class: sorted_by == item ? 'is-active' : ''
end
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index a0b2acd502b..60ff2181a95 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -12,13 +12,14 @@ module Ci
include AtomicInternalId
include EnumWithNil
- belongs_to :project, inverse_of: :pipelines
+ belongs_to :project, inverse_of: :all_pipelines
belongs_to :user
belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline'
belongs_to :pipeline_schedule, class_name: 'Ci::PipelineSchedule'
+ belongs_to :merge_request, class_name: 'MergeRequest'
has_internal_id :iid, scope: :project, presence: false, init: ->(s) do
- s&.project&.pipelines&.maximum(:iid) || s&.project&.pipelines&.count
+ s&.project&.all_pipelines&.maximum(:iid) || s&.project&.all_pipelines&.count
end
has_many :stages, -> { order(position: :asc) }, inverse_of: :pipeline
@@ -50,6 +51,9 @@ module Ci
validates :sha, presence: { unless: :importing? }
validates :ref, presence: { unless: :importing? }
+ validates :merge_request, presence: { if: :merge_request? }
+ validates :merge_request, absence: { unless: :merge_request? }
+ validates :tag, inclusion: { in: [false], if: :merge_request? }
validates :status, presence: { unless: :importing? }
validate :valid_commit_sha, unless: :importing?
@@ -170,6 +174,14 @@ module Ci
end
scope :internal, -> { where(source: internal_sources) }
+ scope :ci_sources, -> { where(config_source: ci_sources_values) }
+
+ scope :sort_by_merge_request_pipelines, -> do
+ sql = 'CASE ci_pipelines.source WHEN (?) THEN 0 ELSE 1 END, ci_pipelines.id DESC'
+ query = ActiveRecord::Base.send(:sanitize_sql_array, [sql, sources[:merge_request]]) # rubocop:disable GitlabSecurity/PublicSend
+
+ order(query)
+ end
scope :for_user, -> (user) { where(user: user) }
@@ -260,6 +272,10 @@ module Ci
sources.reject { |source| source == "external" }.values
end
+ def self.ci_sources_values
+ config_sources.values_at(:repository_source, :auto_devops_source, :unknown_source)
+ end
+
def stages_count
statuses.select(:stage).distinct.count
end
@@ -372,7 +388,7 @@ module Ci
end
def branch?
- !tag?
+ !tag? && !merge_request?
end
def stuck?
@@ -619,7 +635,12 @@ module Ci
# All the merge requests for which the current pipeline runs/ran against
def all_merge_requests
- @all_merge_requests ||= project.merge_requests.where(source_branch: ref)
+ @all_merge_requests ||=
+ if merge_request?
+ project.merge_requests.where(id: merge_request.id)
+ else
+ project.merge_requests.where(source_branch: ref)
+ end
end
def detailed_status(current_user)
@@ -696,6 +717,8 @@ module Ci
def git_ref
if branch?
Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s
+ elsif merge_request?
+ Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s
elsif tag?
Gitlab::Git::TAG_REF_PREFIX + ref.to_s
else
diff --git a/app/models/ci/pipeline_enums.rb b/app/models/ci/pipeline_enums.rb
index 8d8d16e2ec1..c0f16066e0b 100644
--- a/app/models/ci/pipeline_enums.rb
+++ b/app/models/ci/pipeline_enums.rb
@@ -21,7 +21,8 @@ module Ci
trigger: 3,
schedule: 4,
api: 5,
- external: 6
+ external: 6,
+ merge_request: 10
}
end
end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 260348c97b2..2693386443a 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -114,7 +114,8 @@ module Ci
cached_attr_reader :version, :revision, :platform, :architecture, :ip_address, :contacted_at
- chronic_duration_attr :maximum_timeout_human_readable, :maximum_timeout
+ chronic_duration_attr :maximum_timeout_human_readable, :maximum_timeout,
+ error_message: 'Maximum job timeout has a value which could not be accepted'
validates :maximum_timeout, allow_nil: true,
numericality: { greater_than_or_equal_to: 600,
diff --git a/app/models/clusters/kubernetes_namespace.rb b/app/models/clusters/kubernetes_namespace.rb
index 34f5e38ff79..73da6cb37d7 100644
--- a/app/models/clusters/kubernetes_namespace.rb
+++ b/app/models/clusters/kubernetes_namespace.rb
@@ -33,14 +33,12 @@ module Clusters
end
def predefined_variables
- config = YAML.dump(kubeconfig)
-
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables
.append(key: 'KUBE_SERVICE_ACCOUNT', value: service_account_name.to_s)
.append(key: 'KUBE_NAMESPACE', value: namespace.to_s)
.append(key: 'KUBE_TOKEN', value: service_account_token.to_s, public: false)
- .append(key: 'KUBECONFIG', value: config, public: false, file: true)
+ .append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true)
end
end
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index dc8b52105cc..867f0edcb07 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -90,13 +90,11 @@ module Clusters
# Clusters::KubernetesNamespace, so once migration has been completed,
# this 'else' branch will be removed. For more information, please see
# https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22433
- config = YAML.dump(kubeconfig)
-
variables
.append(key: 'KUBE_URL', value: api_url)
.append(key: 'KUBE_TOKEN', value: token, public: false)
.append(key: 'KUBE_NAMESPACE', value: actual_namespace)
- .append(key: 'KUBECONFIG', value: config, public: false, file: true)
+ .append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true)
end
end
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 546fcc54a15..2c89da88b9b 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -298,7 +298,7 @@ class Commit
end
def pipelines
- project.pipelines.where(sha: sha)
+ project.ci_pipelines.where(sha: sha)
end
def last_pipeline
@@ -312,7 +312,7 @@ class Commit
end
def status_for_project(ref, pipeline_project)
- pipeline_project.pipelines.latest_status_per_commit(id, ref)[id]
+ pipeline_project.ci_pipelines.latest_status_per_commit(id, ref)[id]
end
def set_status_for_ref(ref, status)
diff --git a/app/models/commit_collection.rb b/app/models/commit_collection.rb
index dd93af9df64..e349f0fe971 100644
--- a/app/models/commit_collection.rb
+++ b/app/models/commit_collection.rb
@@ -24,7 +24,7 @@ class CommitCollection
# Setting this status ahead of time removes the need for running a query for
# every commit we're displaying.
def with_pipeline_status
- statuses = project.pipelines.latest_status_per_commit(map(&:id), ref)
+ statuses = project.ci_pipelines.latest_status_per_commit(map(&:id), ref)
each do |commit|
commit.set_status_for_ref(ref, statuses[commit.id])
diff --git a/app/models/concerns/chronic_duration_attribute.rb b/app/models/concerns/chronic_duration_attribute.rb
index edf6ac96730..af4905115b1 100644
--- a/app/models/concerns/chronic_duration_attribute.rb
+++ b/app/models/concerns/chronic_duration_attribute.rb
@@ -24,7 +24,7 @@ module ChronicDurationAttribute
end
end
- validates virtual_attribute, allow_nil: true, duration: true
+ validates virtual_attribute, allow_nil: true, duration: { message: parameters[:error_message] }
end
alias_method :chronic_duration_attr, :chronic_duration_attr_writer
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index b2fb79bc7ed..1a8662db9fb 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -6,12 +6,12 @@ class WebHook < ActiveRecord::Base
attr_encrypted :token,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm',
- key: Settings.attr_encrypted_db_key_base_truncated
+ key: Settings.attr_encrypted_db_key_base_32
attr_encrypted :url,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm',
- key: Settings.attr_encrypted_db_key_base_truncated
+ key: Settings.attr_encrypted_db_key_base_32
has_many :web_hook_logs, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 780035c77e2..b7e13bcbccf 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -235,20 +235,6 @@ class Issue < ActiveRecord::Base
def as_json(options = {})
super(options).tap do |json|
- if options.key?(:issue_endpoints) && project
- url_helper = Gitlab::Routing.url_helpers
-
- issue_reference = options[:include_full_project_path] ? to_reference(full: true) : to_reference
-
- json.merge!(
- reference_path: issue_reference,
- real_path: url_helper.project_issue_path(project, self),
- issue_sidebar_endpoint: url_helper.project_issue_path(project, self, format: :json, serializer: 'sidebar'),
- toggle_subscription_endpoint: url_helper.toggle_subscription_project_issue_path(project, self),
- assignable_labels_endpoint: url_helper.project_labels_path(project, format: :json, include_ancestor_groups: true)
- )
- end
-
if options.key?(:labels)
json[:labels] = labels.as_json(
project: project,
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 92add079a02..f40dff7c1bd 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -63,6 +63,7 @@ class MergeRequest < ActiveRecord::Base
dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :cached_closes_issues, through: :merge_requests_closing_issues, source: :issue
+ has_many :merge_request_pipelines, foreign_key: 'merge_request_id', class_name: 'Ci::Pipeline'
belongs_to :assignee, class_name: "User"
@@ -1052,12 +1053,17 @@ class MergeRequest < ActiveRecord::Base
diverged_commits_count > 0
end
- def all_pipelines
+ def all_pipelines(shas: all_commit_shas)
return Ci::Pipeline.none unless source_project
- @all_pipelines ||= source_project.pipelines
- .where(sha: all_commit_shas, ref: source_branch)
- .order(id: :desc)
+ @all_pipelines ||= source_project.ci_pipelines
+ .where(sha: shas, ref: source_branch)
+ .where(merge_request: [nil, self])
+ .sort_by_merge_request_pipelines
+ end
+
+ def merge_request_pipeline_exists?
+ merge_request_pipelines.exists?(sha: diff_head_sha)
end
def has_test_reports?
@@ -1214,7 +1220,7 @@ class MergeRequest < ActiveRecord::Base
end
def base_pipeline
- @base_pipeline ||= project.pipelines
+ @base_pipeline ||= project.ci_pipelines
.order(id: :desc)
.find_by(sha: diff_base_sha)
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 5a35a6a1a2a..587bada469e 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -248,7 +248,17 @@ class Project < ActiveRecord::Base
has_many :container_repositories, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :commit_statuses
- has_many :pipelines, class_name: 'Ci::Pipeline', inverse_of: :project
+ # The relation :all_pipelines is intented to be used when we want to get the
+ # whole list of pipelines associated to the project
+ has_many :all_pipelines, class_name: 'Ci::Pipeline', inverse_of: :project
+ # The relation :ci_pipelines is intented to be used when we want to get only
+ # those pipeline which are directly related to CI. There are
+ # other pipelines, like webide ones, that we won't retrieve
+ # if we use this relation.
+ has_many :ci_pipelines,
+ -> { Feature.enabled?(:pipeline_ci_sources_only, default_enabled: true) ? ci_sources : all },
+ class_name: 'Ci::Pipeline',
+ inverse_of: :project
has_many :stages, class_name: 'Ci::Stage', inverse_of: :project
# Ci::Build objects store data on the file system such as artifact files and
@@ -393,7 +403,8 @@ class Project < ActiveRecord::Base
enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 }
- chronic_duration_attr :build_timeout_human_readable, :build_timeout, default: 3600
+ chronic_duration_attr :build_timeout_human_readable, :build_timeout,
+ default: 3600, error_message: 'Maximum job timeout has a value which could not be accepted'
validates :build_timeout, allow_nil: true,
numericality: { greater_than_or_equal_to: 10.minutes,
@@ -629,7 +640,7 @@ class Project < ActiveRecord::Base
# ref can't be HEAD, can only be branch/tag name or SHA
def latest_successful_builds_for(ref = default_branch)
- latest_pipeline = pipelines.latest_successful_for(ref)
+ latest_pipeline = ci_pipelines.latest_successful_for(ref)
if latest_pipeline
latest_pipeline.builds.latest.with_artifacts_archive
@@ -1155,6 +1166,11 @@ class Project < ActiveRecord::Base
"#{web_url}.git"
end
+ # Is overriden in EE
+ def lfs_http_url_to_repo(_)
+ http_url_to_repo
+ end
+
def forked?
fork_network && fork_network.root_project != self
end
@@ -1385,7 +1401,7 @@ class Project < ActiveRecord::Base
return unless sha
- pipelines.order(id: :desc).find_by(sha: sha, ref: ref)
+ ci_pipelines.order(id: :desc).find_by(sha: sha, ref: ref)
end
def latest_successful_pipeline_for_default_branch
@@ -1394,12 +1410,12 @@ class Project < ActiveRecord::Base
end
@latest_successful_pipeline_for_default_branch =
- pipelines.latest_successful_for(default_branch)
+ ci_pipelines.latest_successful_for(default_branch)
end
def latest_successful_pipeline_for(ref = nil)
if ref && ref != default_branch
- pipelines.latest_successful_for(ref)
+ ci_pipelines.latest_successful_for(ref)
else
latest_successful_pipeline_for_default_branch
end
diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb
index c52a531e5fe..b801fd84a07 100644
--- a/app/models/project_services/kubernetes_service.rb
+++ b/app/models/project_services/kubernetes_service.rb
@@ -110,14 +110,12 @@ class KubernetesService < DeploymentService
# Clusters::Platforms::Kubernetes, it won't be used on this method
# as it's only needed for Clusters::Cluster.
def predefined_variables(project:)
- config = YAML.dump(kubeconfig)
-
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables
.append(key: 'KUBE_URL', value: api_url)
.append(key: 'KUBE_TOKEN', value: token, public: false)
.append(key: 'KUBE_NAMESPACE', value: actual_namespace)
- .append(key: 'KUBECONFIG', value: config, public: false, file: true)
+ .append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true)
if ca_pem.present?
variables
diff --git a/app/models/project_services/pipelines_email_service.rb b/app/models/project_services/pipelines_email_service.rb
index 6f39a5e6e83..d60a6a7efa3 100644
--- a/app/models/project_services/pipelines_email_service.rb
+++ b/app/models/project_services/pipelines_email_service.rb
@@ -38,11 +38,11 @@ class PipelinesEmailService < Service
end
def can_test?
- project.pipelines.any?
+ project.ci_pipelines.any?
end
def test_data(project, user)
- data = Gitlab::DataBuilder::Pipeline.build(project.pipelines.last)
+ data = Gitlab::DataBuilder::Pipeline.build(project.ci_pipelines.last)
data[:user] = user.hook_attrs
data
end
diff --git a/app/serializers/README.md b/app/serializers/README.md
index 0337f88db5f..bb94745b0b5 100644
--- a/app/serializers/README.md
+++ b/app/serializers/README.md
@@ -180,7 +180,7 @@ def index
render json: MyResourceSerializer
.new(current_user: @current_user)
.represent_details(@project.resources)
- nd
+ end
end
```
@@ -196,7 +196,7 @@ def index
.represent_details(@project.resources),
count: @project.resources.count
}
- nd
+ end
end
```
diff --git a/app/serializers/issue_board_entity.rb b/app/serializers/issue_board_entity.rb
new file mode 100644
index 00000000000..58ab804a3c8
--- /dev/null
+++ b/app/serializers/issue_board_entity.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+class IssueBoardEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :id
+ expose :iid
+ expose :title
+
+ expose :confidential
+ expose :due_date
+ expose :project_id
+ expose :relative_position
+
+ expose :project do |issue|
+ API::Entities::Project.represent issue.project, only: [:id, :path]
+ end
+
+ expose :milestone, expose_nil: false do |issue|
+ API::Entities::Project.represent issue.milestone, only: [:id, :title]
+ end
+
+ expose :assignees do |issue|
+ API::Entities::UserBasic.represent issue.assignees, only: [:id, :name, :username, :avatar_url]
+ end
+
+ expose :labels do |issue|
+ LabelEntity.represent issue.labels, project: issue.project, only: [:id, :title, :description, :color, :priority, :text_color]
+ end
+
+ expose :reference_path, if: -> (issue) { issue.project } do |issue, options|
+ options[:include_full_project_path] ? issue.to_reference(full: true) : issue.to_reference
+ end
+
+ expose :real_path, if: -> (issue) { issue.project } do |issue|
+ project_issue_path(issue.project, issue)
+ end
+
+ expose :issue_sidebar_endpoint, if: -> (issue) { issue.project } do |issue|
+ project_issue_path(issue.project, issue, format: :json, serializer: 'sidebar')
+ end
+
+ expose :toggle_subscription_endpoint, if: -> (issue) { issue.project } do |issue|
+ toggle_subscription_project_issue_path(issue.project, issue)
+ end
+
+ expose :assignable_labels_endpoint, if: -> (issue) { issue.project } do |issue|
+ project_labels_path(issue.project, format: :json, include_ancestor_groups: true)
+ end
+end
diff --git a/app/serializers/issue_serializer.rb b/app/serializers/issue_serializer.rb
index 37cf5e28396..d66f0a5acb7 100644
--- a/app/serializers/issue_serializer.rb
+++ b/app/serializers/issue_serializer.rb
@@ -4,15 +4,17 @@ class IssueSerializer < BaseSerializer
# This overrided method takes care of which entity should be used
# to serialize the `issue` based on `basic` key in `opts` param.
# Hence, `entity` doesn't need to be declared on the class scope.
- def represent(merge_request, opts = {})
+ def represent(issue, opts = {})
entity =
case opts[:serializer]
when 'sidebar'
IssueSidebarEntity
+ when 'board'
+ IssueBoardEntity
else
IssueEntity
end
- super(merge_request, opts, entity)
+ super(issue, opts, entity)
end
end
diff --git a/app/serializers/label_entity.rb b/app/serializers/label_entity.rb
index 98743d62b50..5082245dda9 100644
--- a/app/serializers/label_entity.rb
+++ b/app/serializers/label_entity.rb
@@ -12,4 +12,8 @@ class LabelEntity < Grape::Entity
expose :text_color
expose :created_at
expose :updated_at
+
+ expose :priority, if: -> (*) { options.key?(:project) } do |label|
+ label.priority(options[:project])
+ end
end
diff --git a/app/serializers/pipeline_entity.rb b/app/serializers/pipeline_entity.rb
index aef838409e0..477b6710168 100644
--- a/app/serializers/pipeline_entity.rb
+++ b/app/serializers/pipeline_entity.rb
@@ -48,6 +48,7 @@ class PipelineEntity < Grape::Entity
expose :tag?, as: :tag
expose :branch?, as: :branch
+ expose :merge_request?, as: :merge_request
end
expose :commit, using: CommitEntity
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index 46a82377c10..19b5552887f 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -14,7 +14,7 @@ module Ci
Gitlab::Ci::Pipeline::Chain::Populate,
Gitlab::Ci::Pipeline::Chain::Create].freeze
- def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, &block)
+ def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, merge_request: nil, &block)
@pipeline = Ci::Pipeline.new
command = Gitlab::Ci::Pipeline::Chain::Command.new(
@@ -25,6 +25,7 @@ module Ci
before_sha: params[:before],
trigger_request: trigger_request,
schedule: schedule,
+ merge_request: merge_request,
ignore_skip_ci: ignore_skip_ci,
save_incompleted: save_on_errors,
seeds_block: block,
@@ -77,7 +78,7 @@ module Ci
# rubocop: disable CodeReuse/ActiveRecord
def auto_cancelable_pipelines
- project.pipelines
+ project.ci_pipelines
.where(ref: pipeline.ref)
.where.not(id: pipeline.id)
.where.not(sha: project.commit(pipeline.ref).try(:id))
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 28c3219b37b..fe19abf50f6 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -54,6 +54,24 @@ module MergeRequests
merge_request, merge_request.project, current_user, merge_request.assignee)
end
+ def create_merge_request_pipeline(merge_request, user)
+ return unless Feature.enabled?(:ci_merge_request_pipeline,
+ merge_request.source_project,
+ default_enabled: true)
+
+ ##
+ # UpdateMergeRequestsWorker could be retried by an exception.
+ # MR pipelines should not be recreated in such case.
+ return if merge_request.merge_request_pipeline_exists?
+
+ Ci::CreatePipelineService
+ .new(merge_request.source_project, user, ref: merge_request.source_branch)
+ .execute(:merge_request,
+ ignore_skip_ci: true,
+ save_on_errors: false,
+ merge_request: merge_request)
+ end
+
# Returns all origin and fork merge requests from `@project` satisfying passed arguments.
# rubocop: disable CodeReuse/ActiveRecord
def merge_requests_for(source_branch, mr_states: [:opened])
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index 6081a7d1de0..7bb9fa60515 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -25,6 +25,7 @@ module MergeRequests
def after_create(issuable)
todo_service.new_merge_request(issuable, current_user)
issuable.cache_merge_request_closes_issues!(current_user)
+ create_merge_request_pipeline(issuable, current_user)
update_merge_requests_head_pipeline(issuable)
super
@@ -49,18 +50,14 @@ module MergeRequests
merge_request.update(head_pipeline_id: pipeline.id) if pipeline
end
- # rubocop: disable CodeReuse/ActiveRecord
def head_pipeline_for(merge_request)
return unless merge_request.source_project
sha = merge_request.source_branch_sha
return unless sha
- pipelines = merge_request.source_project.pipelines.where(ref: merge_request.source_branch, sha: sha)
-
- pipelines.order(id: :desc).first
+ merge_request.all_pipelines(shas: sha).first
end
- # rubocop: enable CodeReuse/ActiveRecord
def set_projects!
# @project is used to determine whether the user can set the merge request's
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index 5fe48da1cd6..667b5916f38 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -92,6 +92,7 @@ module MergeRequests
end
merge_request.mark_as_unchecked
+ create_merge_request_pipeline(merge_request, current_user)
UpdateHeadPipelineForMergeRequestWorker.perform_async(merge_request.id)
end
diff --git a/app/services/projects/auto_devops/disable_service.rb b/app/services/projects/auto_devops/disable_service.rb
index 1b578a3c5ce..6608b3da1a8 100644
--- a/app/services/projects/auto_devops/disable_service.rb
+++ b/app/services/projects/auto_devops/disable_service.rb
@@ -34,7 +34,7 @@ module Projects
end
def auto_devops_pipelines
- @auto_devops_pipelines ||= project.pipelines.auto_devops_source
+ @auto_devops_pipelines ||= project.ci_pipelines.auto_devops_source
end
end
end
diff --git a/app/services/test_hooks/project_service.rb b/app/services/test_hooks/project_service.rb
index 45e0e61e5c4..7e14ddcd017 100644
--- a/app/services/test_hooks/project_service.rb
+++ b/app/services/test_hooks/project_service.rb
@@ -49,7 +49,7 @@ module TestHooks
end
def pipeline_events_data
- pipeline = project.pipelines.first
+ pipeline = project.ci_pipelines.first
throw(:validation_error, 'Ensure the project has CI pipelines.') unless pipeline.present?
Gitlab::DataBuilder::Pipeline.build(pipeline)
diff --git a/app/validators/duration_validator.rb b/app/validators/duration_validator.rb
index 811828169ca..defd28d7d3b 100644
--- a/app/validators/duration_validator.rb
+++ b/app/validators/duration_validator.rb
@@ -14,6 +14,10 @@ class DurationValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
ChronicDuration.parse(value)
rescue ChronicDuration::DurationParseError
- record.errors.add(attribute, "is not a correct duration")
+ if options[:message]
+ record.errors.add(:base, options[:message])
+ else
+ record.errors.add(attribute, "is not a correct duration")
+ end
end
end
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index f910e90d6ca..600120c4f05 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -9,28 +9,20 @@
.search-holder
.search-field-holder
= search_field_tag :search_query, params[:search_query], placeholder: 'Search by name, email or username', class: 'form-control search-text-input js-search-input', spellcheck: false
+ - if @sort.present?
+ = hidden_field_tag :sort, @sort
= icon("search", class: "search-icon")
- .dropdown
- - toggle_text = if @sort.present? then sort_options_hash[@sort] else sort_title_name end
+ = button_tag 'Search users' if Rails.env.test?
+ .dropdown.user-sort-dropdown
+ - toggle_text = if @sort.present? then users_sort_options_hash[@sort] else sort_title_name end
= dropdown_toggle(toggle_text, { toggle: 'dropdown' })
%ul.dropdown-menu.dropdown-menu-right
%li.dropdown-header
Sort by
%li
- = link_to admin_users_path(sort: sort_value_name, filter: params[:filter]) do
- = sort_title_name
- = link_to admin_users_path(sort: sort_value_recently_signin, filter: params[:filter]) do
- = sort_title_recently_signin
- = link_to admin_users_path(sort: sort_value_oldest_signin, filter: params[:filter]) do
- = sort_title_oldest_signin
- = link_to admin_users_path(sort: sort_value_recently_created, filter: params[:filter]) do
- = sort_title_recently_created
- = link_to admin_users_path(sort: sort_value_oldest_created, filter: params[:filter]) do
- = sort_title_oldest_created
- = link_to admin_users_path(sort: sort_value_recently_updated, filter: params[:filter]) do
- = sort_title_recently_updated
- = link_to admin_users_path(sort: sort_value_oldest_updated, filter: params[:filter]) do
- = sort_title_oldest_updated
+ - users_sort_options_hash.each do |value, title|
+ = link_to admin_users_path(sort: value, filter: params[:filter], search_query: params[:search_query]) do
+ = title
= link_to 'New user', new_admin_user_path, class: 'btn btn-success btn-search'
.top-area.scrolling-tabs-container.inner-page-scroll-tabs
diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml
index 621b7922072..bb328f5344c 100644
--- a/app/views/projects/settings/ci_cd/_form.html.haml
+++ b/app/views/projects/settings/ci_cd/_form.html.haml
@@ -29,7 +29,7 @@
= f.label :build_timeout_human_readable, _('Timeout'), class: 'label-bold'
= f.text_field :build_timeout_human_readable, class: 'form-control'
%p.form-text.text-muted
- = _("Per job. If a job passes this threshold, it will be marked as failed")
+ = _('If any job surpasses this timeout threshold, it will be marked as failed. Human readable time input language is accepted like "1 hour". Values without specification represent seconds.')
= link_to icon('question-circle'), help_page_path('user/project/pipelines/settings', anchor: 'timeout'), target: '_blank'
%hr
diff --git a/app/views/shared/runners/_form.html.haml b/app/views/shared/runners/_form.html.haml
index daf08d9bb2c..559b5aa9c1e 100644
--- a/app/views/shared/runners/_form.html.haml
+++ b/app/views/shared/runners/_form.html.haml
@@ -45,7 +45,7 @@
= _('Maximum job timeout')
.col-sm-10
= f.text_field :maximum_timeout_human_readable, class: 'form-control'
- .form-text.text-muted= _('This timeout will take precedence when lower than Project-defined timeout')
+ .form-text.text-muted= _('This timeout will take precedence when lower than project-defined timeout and accepts a human readable time input language like "1 hour". Values without specification represent seconds.')
.form-group.row
= label_tag :tag_list, class: 'col-form-label col-sm-2' do
= _('Tags')
diff --git a/app/workers/update_head_pipeline_for_merge_request_worker.rb b/app/workers/update_head_pipeline_for_merge_request_worker.rb
index 9ce51662969..e8494ffa002 100644
--- a/app/workers/update_head_pipeline_for_merge_request_worker.rb
+++ b/app/workers/update_head_pipeline_for_merge_request_worker.rb
@@ -6,10 +6,11 @@ class UpdateHeadPipelineForMergeRequestWorker
queue_namespace :pipeline_processing
- # rubocop: disable CodeReuse/ActiveRecord
def perform(merge_request_id)
merge_request = MergeRequest.find(merge_request_id)
- pipeline = Ci::Pipeline.where(project: merge_request.source_project, ref: merge_request.source_branch).last
+
+ sha = merge_request.diff_head_sha
+ pipeline = merge_request.all_pipelines(shas: sha).first
return unless pipeline && pipeline.latest?
@@ -21,7 +22,6 @@ class UpdateHeadPipelineForMergeRequestWorker
merge_request.update_attribute(:head_pipeline_id, pipeline.id)
end
- # rubocop: enable CodeReuse/ActiveRecord
def log_error_message_for(merge_request)
Rails.logger.error(