<script> <script>
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import DiffGutterAvatars from './diff_gutter_avatars.vue'; import DiffGutterAvatars from './diff_gutter_avatars.vue';
import { LINE_POSITION_RIGHT } from '../constants'; import { LINE_POSITION_RIGHT } from '../constants';
...@@ -98,7 +99,8 @@ export default { ...@@ -98,7 +99,8 @@ export default {
return this.showCommentButton && this.hasDiscussions; return this.showCommentButton && this.hasDiscussions;
}, },
shouldRenderCommentButton() { shouldRenderCommentButton() {
return this.isLoggedIn && this.showCommentButton; const isDiffHead = parseBoolean(getParameterByName('diff_head'));
return !isDiffHead && this.isLoggedIn && this.showCommentButton;
}, },
}, },
methods: { methods: {
...@@ -130,6 +132,7 @@ export default { ...@@ -130,6 +132,7 @@ export default {
</button> </button>
<a <a
v-if="lineNumber" v-if="lineNumber"
ref="lineNumberRef"
:data-linenumber="lineNumber" :data-linenumber="lineNumber"
:href="lineHref" :href="lineHref"
@click="setHighlightedRow(lineCode)" @click="setHighlightedRow(lineCode)"
... ...
......
...@@ -327,7 +327,10 @@ export const getSelectedFragment = restrictToNode => { ...@@ -327,7 +327,10 @@ export const getSelectedFragment = restrictToNode => {
documentFragment.originalNodes.push(range.commonAncestorContainer); documentFragment.originalNodes.push(range.commonAncestorContainer);
} }
} }
if (documentFragment.textContent.length === 0) return null;
if (documentFragment.textContent.length === 0 && documentFragment.children.length === 0) {
return null;
}
return documentFragment; return documentFragment;
}; };
... ...
......
...@@ -8,7 +8,6 @@ module Ci ...@@ -8,7 +8,6 @@ module Ci
include Importable include Importable
include AfterCommitQueue include AfterCommitQueue
include HasRef include HasRef
include Gitlab::Utils::StrongMemoize
InvalidBridgeTypeError = Class.new(StandardError) InvalidBridgeTypeError = Class.new(StandardError)
... ...
......
...@@ -10,7 +10,6 @@ module Ci ...@@ -10,7 +10,6 @@ module Ci
include ObjectStorage::BackgroundMove include ObjectStorage::BackgroundMove
include Presentable include Presentable
include Importable include Importable
include Gitlab::Utils::StrongMemoize
include HasRef include HasRef
include IgnorableColumns include IgnorableColumns
... ...
......
...@@ -2,10 +2,14 @@ ...@@ -2,10 +2,14 @@
module Ci module Ci
class Processable < ::CommitStatus class Processable < ::CommitStatus
include Gitlab::Utils::StrongMemoize
has_many :needs, class_name: 'Ci::BuildNeed', foreign_key: :build_id, inverse_of: :build has_many :needs, class_name: 'Ci::BuildNeed', foreign_key: :build_id, inverse_of: :build
accepts_nested_attributes_for :needs accepts_nested_attributes_for :needs
enum scheduling_type: { stage: 0, dag: 1 }, _prefix: true
scope :preload_needs, -> { preload(:needs) } scope :preload_needs, -> { preload(:needs) }
def self.select_with_aggregated_needs(project) def self.select_with_aggregated_needs(project)
...@@ -23,6 +27,7 @@ module Ci ...@@ -23,6 +27,7 @@ module Ci
end end
validates :type, presence: true validates :type, presence: true
validates :scheduling_type, presence: true, on: :create, if: :validate_scheduling_type?
def aggregated_needs_names def aggregated_needs_names
read_attribute(:aggregated_needs_names) read_attribute(:aggregated_needs_names)
...@@ -47,5 +52,19 @@ module Ci ...@@ -47,5 +52,19 @@ module Ci
def scoped_variables_hash def scoped_variables_hash
raise NotImplementedError raise NotImplementedError
end end
# scheduling_type column of previous builds/bridges have not been populated,
# so we calculate this value on runtime when we need it.
def find_legacy_scheduling_type
strong_memoize(:find_legacy_scheduling_type) do
needs.exists? ? :dag : :stage
end
end
private
def validate_scheduling_type?
!importing? && Feature.enabled?(:validate_scheduling_type_of_processables, project)
end
end end
end end
...@@ -30,7 +30,8 @@ module Clusters ...@@ -30,7 +30,8 @@ module Clusters
version: VERSION, version: VERSION,
rbac: cluster.platform_kubernetes_rbac?, rbac: cluster.platform_kubernetes_rbac?,
chart: chart, chart: chart,
files: files files: files,
postinstall: post_install_script
) )
end end
...@@ -43,6 +44,10 @@ module Clusters ...@@ -43,6 +44,10 @@ module Clusters
) )
end end
def files
super.merge('wait-for-elasticsearch.sh': File.read("#{Rails.root}/vendor/elastic_stack/wait-for-elasticsearch.sh"))
end
def elasticsearch_client def elasticsearch_client
strong_memoize(:elasticsearch_client) do strong_memoize(:elasticsearch_client) do
next unless kube_client next unless kube_client
...@@ -69,10 +74,16 @@ module Clusters ...@@ -69,10 +74,16 @@ module Clusters
private private
def post_install_script
[
"timeout -t60 sh /data/helm/elastic-stack/config/wait-for-elasticsearch.sh http://elastic-stack-elasticsearch-client:9200"
]
end
def post_delete_script def post_delete_script
[ [
Gitlab::Kubernetes::KubectlCmd.delete("pvc", "--selector", "release=elastic-stack") Gitlab::Kubernetes::KubectlCmd.delete("pvc", "--selector", "release=elastic-stack")
].compact ]
end end
def kube_client def kube_client
... ...
......
...@@ -5,7 +5,7 @@ module Ci ...@@ -5,7 +5,7 @@ module Ci
CLONE_ACCESSORS = %i[pipeline project ref tag options name CLONE_ACCESSORS = %i[pipeline project ref tag options name
allow_failure stage stage_id stage_idx trigger_request allow_failure stage stage_id stage_idx trigger_request
yaml_variables when environment coverage_regex yaml_variables when environment coverage_regex
description tag_list protected needs resource_group].freeze description tag_list protected needs resource_group scheduling_type].freeze
def execute(build) def execute(build)
reprocess!(build).tap do |new_build| reprocess!(build).tap do |new_build|
...@@ -27,9 +27,10 @@ module Ci ...@@ -27,9 +27,10 @@ module Ci
attributes = CLONE_ACCESSORS.map do |attribute| attributes = CLONE_ACCESSORS.map do |attribute|
[attribute, build.public_send(attribute)] # rubocop:disable GitlabSecurity/PublicSend [attribute, build.public_send(attribute)] # rubocop:disable GitlabSecurity/PublicSend
end end.to_h
attributes.push([:user, current_user]) attributes[:user] = current_user
attributes[:scheduling_type] ||= build.find_legacy_scheduling_type
Ci::Build.transaction do Ci::Build.transaction do
# mark all other builds of that name as retried # mark all other builds of that name as retried
...@@ -49,7 +50,7 @@ module Ci ...@@ -49,7 +50,7 @@ module Ci
private private
def create_build!(attributes) def create_build!(attributes)
build = project.builds.new(Hash[attributes]) build = project.builds.new(attributes)
build.deployment = ::Gitlab::Ci::Pipeline::Seed::Deployment.new(build).to_resource build.deployment = ::Gitlab::Ci::Pipeline::Seed::Deployment.new(build).to_resource
build.retried = false build.retried = false
build.save! build.save!
... ...
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
":title" => '(list.assignee && list.assignee.username || "")' } ":title" => '(list.assignee && list.assignee.username || "")' }
@{{ list.assignee.username }} @{{ list.assignee.username }}
%span.has-tooltip.badge.color-label.title{ "v-if": "list.type === \"label\"", %span.has-tooltip.badge.color-label.title.d-inline-block.mw-100.text-truncate.align-middle{ "v-if": "list.type === \"label\"",
":title" => '(list.label ? list.label.description : "")', ":title" => '(list.label ? list.label.description : "")',
data: { container: "body", placement: "bottom" }, data: { container: "body", placement: "bottom" },
":style" => "{ backgroundColor: (list.label && list.label.color ? list.label.color : null), color: (list.label && list.label.textColor ? list.label.textColor : \"#2e2e2e\") }" } ":style" => "{ backgroundColor: (list.label && list.label.color ? list.label.color : null), color: (list.label && list.label.textColor ? list.label.textColor : \"#2e2e2e\") }" }
... ...
......
---
title: Fix copy markdown with elements with no text content
merge_request: 24020
author:
type: fixed
---
title: Implement support of allow_failure keyword for CI rules
merge_request: 24605
author:
type: added
---
title: Wait for elasticsearch to be green on install
merge_request: 24489
author:
type: added
---
title: Hide comment button if on diff HEAD
merge_request: 24207
author:
type: changed
---
title: Add styles for board list labels when text is too long
merge_request: 24627
author:
type: fixed
...@@ -165,9 +165,10 @@ class Gitlab::Seeder::Pipelines ...@@ -165,9 +165,10 @@ class Gitlab::Seeder::Pipelines
end end
def job_attributes(pipeline, opts) def job_attributes(pipeline, opts)
{ name: 'test build', stage: 'test', stage_idx: stage_index(opts[:stage]), {
name: 'test build', stage: 'test', stage_idx: stage_index(opts[:stage]),
ref: pipeline.ref, tag: false, user: build_user, project: @project, pipeline: pipeline, ref: pipeline.ref, tag: false, user: build_user, project: @project, pipeline: pipeline,
created_at: Time.now, updated_at: Time.now scheduling_type: :stage, created_at: Time.now, updated_at: Time.now
}.merge(opts) }.merge(opts)
end end
... ...
......
# frozen_string_literal: true
class AddSchedulingTypeToCiBuilds < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_builds, :scheduling_type, :integer, limit: 2
end
end
...@@ -677,6 +677,7 @@ ActiveRecord::Schema.define(version: 2020_02_11_152410) do ...@@ -677,6 +677,7 @@ ActiveRecord::Schema.define(version: 2020_02_11_152410) do
t.bigint "resource_group_id" t.bigint "resource_group_id"
t.datetime_with_timezone "waiting_for_resource_at" t.datetime_with_timezone "waiting_for_resource_at"
t.boolean "processed" t.boolean "processed"
t.integer "scheduling_type", limit: 2
t.index ["artifacts_expire_at"], name: "index_ci_builds_on_artifacts_expire_at", where: "(artifacts_file <> ''::text)" t.index ["artifacts_expire_at"], name: "index_ci_builds_on_artifacts_expire_at", where: "(artifacts_file <> ''::text)"
t.index ["auto_canceled_by_id"], name: "index_ci_builds_on_auto_canceled_by_id" t.index ["auto_canceled_by_id"], name: "index_ci_builds_on_auto_canceled_by_id"
t.index ["commit_id", "artifacts_expire_at", "id"], name: "index_ci_builds_on_commit_id_and_artifacts_expireatandidpartial", where: "(((type)::text = 'Ci::Build'::text) AND ((retried = false) OR (retried IS NULL)) AND ((name)::text = ANY (ARRAY[('sast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('sast:container'::character varying)::text, ('container_scanning'::character varying)::text, ('dast'::character varying)::text])))" t.index ["commit_id", "artifacts_expire_at", "id"], name: "index_ci_builds_on_commit_id_and_artifacts_expireatandidpartial", where: "(((type)::text = 'Ci::Build'::text) AND ((retried = false) OR (retried IS NULL)) AND ((name)::text = ANY (ARRAY[('sast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('sast:container'::character varying)::text, ('container_scanning'::character varying)::text, ('dast'::character varying)::text])))"
... ...
......
...@@ -851,7 +851,7 @@ In this example, if the first rule: ...@@ -851,7 +851,7 @@ In this example, if the first rule:
- Matches, the job will be given the `when:always` attribute. - Matches, the job will be given the `when:always` attribute.
- Does not match, the second and third rules will be evaluated sequentially - Does not match, the second and third rules will be evaluated sequentially
until a match is found. That is, the job will be given either the: until a match is found. That is, the job will be given either the:
- `when: manual` attribute if the second rule matches. - `when: manual` attribute if the second rule matches. **The stage will not complete until this manual job is triggered and completes successfully.**
- `when: on_success` attribute if the second rule does not match. The third - `when: on_success` attribute if the second rule does not match. The third
rule will always match when reached because it has no conditional clauses. rule will always match when reached because it has no conditional clauses.
...@@ -937,6 +937,25 @@ NOTE: **Note:** ...@@ -937,6 +937,25 @@ NOTE: **Note:**
For performance reasons, using `exists` with patterns is limited to 10000 For performance reasons, using `exists` with patterns is limited to 10000
checks. After the 10000th check, rules with patterned globs will always match. checks. After the 10000th check, rules with patterned globs will always match.
#### `rules:allow_failure`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/30235) in GitLab 12.8.
You can use [`allow_failure: true`](#allow_failure) within `rules:` to allow a job to fail, or a manual job to
wait for action, without stopping the pipeline itself. All jobs using `rules:` default to `allow_failure: false`
if `allow_failure:` is not defined.
```yaml
job:
script: "echo Hello, Rules!"
rules:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
when: manual
allow_failure: true
```
In this example, if the first rule matches, then the job will have `when: manual` and `allow_failure: true`.
#### Complex rule clauses #### Complex rule clauses
To conjoin `if`, `changes`, and `exists` clauses with an AND, use them in the To conjoin `if`, `changes`, and `exists` clauses with an AND, use them in the
...@@ -976,6 +995,7 @@ The only job attributes currently set by `rules` are: ...@@ -976,6 +995,7 @@ The only job attributes currently set by `rules` are:
- `when`. - `when`.
- `start_in`, if `when` is set to `delayed`. - `start_in`, if `when` is set to `delayed`.
- `allow_failure`.
A job will be included in a pipeline if `when` is evaluated to any value A job will be included in a pipeline if `when` is evaluated to any value
except `never`. except `never`.
... ...
......
...@@ -464,8 +464,8 @@ chart is used to install this application with a ...@@ -464,8 +464,8 @@ chart is used to install this application with a
file. file.
NOTE: **Note:** NOTE: **Note:**
The chart will deploy 4 Elasticsearch nodes: 2 masters, 1 data and 1 client node, The chart will deploy 5 Elasticsearch nodes: 2 masters, 2 data and 1 client node,
with resource requests totalling 0.1 CPU and 3GB RAM. Each data node requests 1.5GB of memory, with resource requests totalling 0.125 CPU and 4.5GB RAM. Each data node requests 1.5GB of memory,
which makes it incompatible with clusters of `f1-micro` and `g1-small` instance types. which makes it incompatible with clusters of `f1-micro` and `g1-small` instance types.
## Install using GitLab CI (alpha) ## Install using GitLab CI (alpha)
... ...
......
...@@ -241,9 +241,10 @@ and give all group members access to the project at once. ...@@ -241,9 +241,10 @@ and give all group members access to the project at once.
Alternatively, you can [lock the sharing with group feature](#share-with-group-lock). Alternatively, you can [lock the sharing with group feature](#share-with-group-lock).
## Sharing a group with another group ## Sharing a group with another group **(CORE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/18328) in GitLab 12.7. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/18328) in GitLab 12.7.
> This feature has been [disabled on GitLab.com](https://gitlab.com/gitlab-com/gl-infra/production/issues/1635).
Similarly to [sharing a project with a group](#sharing-a-project-with-a-group), Similarly to [sharing a project with a group](#sharing-a-project-with-a-group),
you can share a group with another group to give direct group members access you can share a group with another group to give direct group members access
... ...
......
...@@ -6,11 +6,12 @@ module Gitlab ...@@ -6,11 +6,12 @@ module Gitlab
class Rules class Rules
include ::Gitlab::Utils::StrongMemoize include ::Gitlab::Utils::StrongMemoize
Result = Struct.new(:when, :start_in) do Result = Struct.new(:when, :start_in, :allow_failure) do
def build_attributes def build_attributes
{ {
when: self.when, when: self.when,
options: { start_in: start_in }.compact options: { start_in: start_in }.compact,
allow_failure: allow_failure
}.compact }.compact
end end
...@@ -30,7 +31,8 @@ module Gitlab ...@@ -30,7 +31,8 @@ module Gitlab
elsif matched_rule = match_rule(pipeline, context) elsif matched_rule = match_rule(pipeline, context)
Result.new( Result.new(
matched_rule.attributes[:when] || @default_when, matched_rule.attributes[:when] || @default_when,
matched_rule.attributes[:start_in] matched_rule.attributes[:start_in],
matched_rule.attributes[:allow_failure]
) )
else else
Result.new('never') Result.new('never')
... ...
......