Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
1c568d834d
commit
023e050d82
|
@ -2,11 +2,15 @@
|
|||
|
||||
require 'gitlab-dangerfiles'
|
||||
|
||||
Gitlab::Dangerfiles.import_plugins(danger)
|
||||
danger.import_plugin('danger/plugins/*.rb')
|
||||
gitlab_dangerfiles = Gitlab::Dangerfiles::Engine.new(self)
|
||||
gitlab_dangerfiles.import_plugins
|
||||
|
||||
return if helper.release_automation?
|
||||
|
||||
danger.import_plugin('danger/plugins/*.rb')
|
||||
|
||||
gitlab_dangerfiles.import_dangerfiles
|
||||
|
||||
project_helper.rule_names.each do |rule|
|
||||
danger.import_dangerfile(path: File.join('danger', rule))
|
||||
end
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -403,7 +403,7 @@ group :development, :test do
|
|||
end
|
||||
|
||||
group :development, :test, :danger do
|
||||
gem 'gitlab-dangerfiles', '~> 1.1.1', require: false
|
||||
gem 'gitlab-dangerfiles', '~> 2.0.0', require: false
|
||||
end
|
||||
|
||||
group :development, :test, :coverage do
|
||||
|
|
|
@ -447,7 +447,7 @@ GEM
|
|||
terminal-table (~> 1.5, >= 1.5.1)
|
||||
gitlab-chronic (0.10.5)
|
||||
numerizer (~> 0.2)
|
||||
gitlab-dangerfiles (1.1.1)
|
||||
gitlab-dangerfiles (2.0.0)
|
||||
danger-gitlab
|
||||
gitlab-experiment (0.5.3)
|
||||
activesupport (>= 3.0)
|
||||
|
@ -1449,7 +1449,7 @@ DEPENDENCIES
|
|||
gitaly (~> 13.11.0.pre.rc1)
|
||||
github-markup (~> 1.7.0)
|
||||
gitlab-chronic (~> 0.10.5)
|
||||
gitlab-dangerfiles (~> 1.1.1)
|
||||
gitlab-dangerfiles (~> 2.0.0)
|
||||
gitlab-experiment (~> 0.5.3)
|
||||
gitlab-fog-azure-rm (~> 1.0.1)
|
||||
gitlab-fog-google (~> 1.13)
|
||||
|
|
|
@ -282,10 +282,12 @@ export default {
|
|||
</template>
|
||||
<template #default>
|
||||
<gl-datepicker
|
||||
v-if="!isLoading"
|
||||
ref="datePicker"
|
||||
class="gl-relative"
|
||||
:default-date="parsedDate"
|
||||
show-clear-button
|
||||
autocomplete="off"
|
||||
@input="setDate"
|
||||
@clear="setDate(null)"
|
||||
/>
|
||||
|
|
|
@ -13,14 +13,6 @@ module Analytics
|
|||
end
|
||||
end
|
||||
|
||||
def project_analytics_navbar_links(project, current_user)
|
||||
[
|
||||
cycle_analytics_navbar_link(project, current_user),
|
||||
repository_analytics_navbar_link(project, current_user),
|
||||
ci_cd_analytics_navbar_link(project, current_user)
|
||||
].compact
|
||||
end
|
||||
|
||||
def group_analytics_navbar_links(group, current_user)
|
||||
[]
|
||||
end
|
||||
|
@ -30,39 +22,6 @@ module Analytics
|
|||
def navbar_sub_item(args)
|
||||
NavbarSubItem.new(**args)
|
||||
end
|
||||
|
||||
def cycle_analytics_navbar_link(project, current_user)
|
||||
return unless project_nav_tab?(:cycle_analytics)
|
||||
|
||||
navbar_sub_item(
|
||||
title: _('Value Stream'),
|
||||
path: 'cycle_analytics#show',
|
||||
link: project_cycle_analytics_path(project),
|
||||
link_to_options: { class: 'shortcuts-project-cycle-analytics' }
|
||||
)
|
||||
end
|
||||
|
||||
def repository_analytics_navbar_link(project, current_user)
|
||||
return if project.empty_repo?
|
||||
|
||||
navbar_sub_item(
|
||||
title: _('Repository'),
|
||||
path: 'graphs#charts',
|
||||
link: charts_project_graph_path(project, current_ref),
|
||||
link_to_options: { class: 'shortcuts-repository-charts' }
|
||||
)
|
||||
end
|
||||
|
||||
def ci_cd_analytics_navbar_link(project, current_user)
|
||||
return unless project_nav_tab?(:pipelines)
|
||||
return unless project.feature_available?(:builds, current_user) || !project.empty_repo?
|
||||
|
||||
navbar_sub_item(
|
||||
title: _('CI/CD'),
|
||||
path: 'pipelines#charts',
|
||||
link: charts_project_pipelines_path(project)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -83,5 +83,4 @@ module AppearancesHelper
|
|||
end
|
||||
end
|
||||
|
||||
AppearancesHelper.prepend_if_ee('EE::AppearancesHelper')
|
||||
AppearancesHelper.prepend_if_jh('JH::AppearancesHelper')
|
||||
AppearancesHelper.prepend_mod
|
||||
|
|
|
@ -409,5 +409,4 @@ module ApplicationHelper
|
|||
end
|
||||
end
|
||||
|
||||
ApplicationHelper.prepend_if_ee('EE::ApplicationHelper')
|
||||
ApplicationHelper.prepend_if_jh('JH::ApplicationHelper')
|
||||
ApplicationHelper.prepend_mod
|
||||
|
|
|
@ -10,6 +10,7 @@ module Ci
|
|||
Gitlab::Ci::Pipeline::Chain::Build::Associations,
|
||||
Gitlab::Ci::Pipeline::Chain::Validate::Abilities,
|
||||
Gitlab::Ci::Pipeline::Chain::Validate::Repository,
|
||||
Gitlab::Ci::Pipeline::Chain::Validate::SecurityOrchestrationPolicy,
|
||||
Gitlab::Ci::Pipeline::Chain::Config::Content,
|
||||
Gitlab::Ci::Pipeline::Chain::Config::Process,
|
||||
Gitlab::Ci::Pipeline::Chain::RemoveUnwantedChatJobs,
|
||||
|
|
|
@ -28,6 +28,13 @@ module Ci
|
|||
def create_pipeline!
|
||||
build_pipeline.tap do |pipeline|
|
||||
pipeline.stages << terminal_stage_seed(pipeline).to_resource
|
||||
|
||||
if Feature.enabled?(:ci_pipeline_ensure_iid_on_save, pipeline.project, default_enabled: :yaml)
|
||||
# Project iid must be called outside a transaction, so we ensure it is set here
|
||||
# otherwise it may be set within the save! which it will lock the InternalId row for the whole transaction
|
||||
pipeline.ensure_project_iid!
|
||||
end
|
||||
|
||||
pipeline.save!
|
||||
|
||||
Ci::ProcessPipelineService
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
- if project_nav_tab? :analytics
|
||||
= render 'layouts/nav/sidebar/analytics_links', links: project_analytics_navbar_links(@project, current_user)
|
||||
|
||||
- if project_nav_tab?(:confluence)
|
||||
- confluence_url = project_wikis_confluence_path(@project)
|
||||
= nav_link do
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Implement variables for pipeline workflow rules
|
||||
merge_request: 59970
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Disable autocomplete for due date in issue sidebar to prevent triggering updates on Chrome
|
||||
merge_request: 60973
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Include other cols in index for pending builds
|
||||
merge_request: 60997
|
||||
author:
|
||||
type: performance
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix changelog Dangerfile to convert MR IID to a string before comparison
|
||||
merge_request: 60899
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Added type field into Issues API
|
||||
merge_request: 59648
|
||||
author: Raimund Hook @stingrayza
|
||||
type: added
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: ci_pipeline_ensure_iid_on_save
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59341
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/327662
|
||||
milestone: '13.12'
|
||||
type: development
|
||||
group: group::code review
|
||||
default_enabled: false
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: ci_pipeline_ensure_iid_on_skip
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59342
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/327661
|
||||
milestone: '13.12'
|
||||
type: development
|
||||
group: group::code review
|
||||
default_enabled: false
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/300997
|
|||
milestone: '13.11'
|
||||
type: development
|
||||
group: group::pipeline authoring
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: escalation_policies_mvc
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60524
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/329347
|
||||
milestone: '13.12'
|
||||
type: development
|
||||
group: group::monitor
|
||||
default_enabled: false
|
|
@ -3,42 +3,50 @@
|
|||
require 'active_support/inflector'
|
||||
|
||||
module InjectEnterpriseEditionModule
|
||||
def prepend_if_ee(constant, with_descendants: false)
|
||||
return unless Gitlab.ee?
|
||||
|
||||
prepend_module(constant.constantize, with_descendants)
|
||||
def prepend_if_ee(constant_with_prefix, namespace: Object, with_descendants: false)
|
||||
prepend_mod_for(
|
||||
constant_without_prefix(constant_with_prefix),
|
||||
namespace: namespace,
|
||||
with_descendants: with_descendants)
|
||||
end
|
||||
|
||||
def extend_if_ee(constant)
|
||||
extend(constant.constantize) if Gitlab.ee?
|
||||
def extend_if_ee(constant_with_prefix, namespace: Object)
|
||||
each_extension_for(
|
||||
constant_without_prefix(constant_with_prefix),
|
||||
namespace,
|
||||
&method(:extend))
|
||||
end
|
||||
|
||||
def include_if_ee(constant)
|
||||
include(constant.constantize) if Gitlab.ee?
|
||||
def include_if_ee(constant_with_prefix, namespace: Object)
|
||||
each_extension_for(
|
||||
constant_without_prefix(constant_with_prefix),
|
||||
namespace,
|
||||
&method(:include))
|
||||
end
|
||||
|
||||
def prepend_ee_mod(with_descendants: false)
|
||||
return unless Gitlab.ee?
|
||||
|
||||
prepend_module(ee_module, with_descendants)
|
||||
def prepend_mod(with_descendants: false)
|
||||
prepend_mod_for(name, with_descendants: with_descendants)
|
||||
end
|
||||
alias_method :prepend_ee_mod, :prepend_mod
|
||||
|
||||
def extend_ee_mod
|
||||
extend(ee_module) if Gitlab.ee?
|
||||
def extend_mod
|
||||
each_extension_for(name, Object, &method(:extend))
|
||||
end
|
||||
alias_method :extend_ee_mod, :extend_mod
|
||||
|
||||
def include_ee_mod
|
||||
include(ee_module) if Gitlab.ee?
|
||||
end
|
||||
|
||||
def prepend_if_jh(constant, with_descendants: false)
|
||||
return unless Gitlab.jh?
|
||||
|
||||
prepend_module(constant.constantize, with_descendants)
|
||||
def include_mod
|
||||
each_extension_for(name, Object, &method(:include))
|
||||
end
|
||||
alias_method :include_ee_mod, :include_mod
|
||||
|
||||
private
|
||||
|
||||
def prepend_mod_for(constant_name, namespace: Object, with_descendants: false)
|
||||
each_extension_for(constant_name, namespace) do |constant|
|
||||
prepend_module(constant, with_descendants)
|
||||
end
|
||||
end
|
||||
|
||||
def prepend_module(mod, with_descendants)
|
||||
prepend(mod)
|
||||
|
||||
|
@ -47,8 +55,34 @@ module InjectEnterpriseEditionModule
|
|||
end
|
||||
end
|
||||
|
||||
def ee_module
|
||||
::EE.const_get(name, false)
|
||||
def each_extension_for(constant_name, namespace)
|
||||
Gitlab.extensions.each do |extension_name|
|
||||
extension_namespace =
|
||||
const_get_maybe_false(namespace, extension_name.upcase)
|
||||
|
||||
extension_module =
|
||||
const_get_maybe_false(extension_namespace, constant_name)
|
||||
|
||||
yield(extension_module) if extension_module
|
||||
end
|
||||
end
|
||||
|
||||
def const_get_maybe_false(mod, name)
|
||||
# We're still heavily relying on Rails autoloading instead of zeitwerk,
|
||||
# therefore this check: `mod.const_defined?(name, false)`
|
||||
# Is not reliable, which may return false while it's defined.
|
||||
# After we moved everything over to zeitwerk we can avoid rescuing
|
||||
# NameError and just check if const_defined?
|
||||
# mod && mod.const_defined?(name, false) && mod.const_get(name, false)
|
||||
mod && mod.const_get(name, false)
|
||||
rescue NameError
|
||||
false
|
||||
end
|
||||
|
||||
def constant_without_prefix(constant_with_prefix)
|
||||
constant_with_prefix
|
||||
.delete_prefix('::') # TODO: Some calling sites are passing this prefix
|
||||
.delete_prefix('EE::')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -38,16 +38,17 @@ end
|
|||
def check_changelog_yaml(path)
|
||||
raw_file = File.read(path)
|
||||
yaml = YAML.safe_load(raw_file)
|
||||
yaml_merge_request = yaml["merge_request"].to_s
|
||||
|
||||
fail "`title` should be set, in #{helper.html_link(path)}! #{SEE_DOC}" if yaml["title"].nil?
|
||||
fail "`type` should be set, in #{helper.html_link(path)}! #{SEE_DOC}" if yaml["type"].nil?
|
||||
|
||||
return if helper.security_mr?
|
||||
return if helper.mr_iid.to_s.empty?
|
||||
return if helper.mr_iid.empty?
|
||||
|
||||
cherry_pick_against_stable_branch = helper.cherry_pick_mr? && helper.stable_branch?
|
||||
|
||||
if yaml["merge_request"].nil?
|
||||
if yaml_merge_request.empty?
|
||||
mr_line = raw_file.lines.find_index("merge_request:\n")
|
||||
|
||||
if mr_line
|
||||
|
@ -55,7 +56,7 @@ def check_changelog_yaml(path)
|
|||
else
|
||||
message "Consider setting `merge_request` to #{helper.mr_iid} in #{helper.html_link(path)}. #{SEE_DOC}"
|
||||
end
|
||||
elsif yaml["merge_request"] != helper.mr_iid && !cherry_pick_against_stable_branch
|
||||
elsif yaml_merge_request != helper.mr_iid && !cherry_pick_against_stable_branch
|
||||
fail "Merge request ID was not set to #{helper.mr_iid}! #{SEE_DOC}"
|
||||
end
|
||||
rescue Psych::Exception
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# FIXME: git.info_for_file raises the following error
|
||||
# /usr/local/bundle/gems/git-1.4.0/lib/git/lib.rb:956:in `command': (Danger::DSLError)
|
||||
# [!] Invalid `Dangerfile` file:
|
||||
# [!] Invalid `Dangerfile` file: git '--git-dir=/builds/gitlab-org/gitlab/.git' '--work-tree=/builds/gitlab-org/gitlab' cat-file '-t' '' 2>&1:fatal: Not a valid object name
|
||||
# This seems to be the same as https://github.com/danger/danger/issues/535.
|
||||
|
||||
# locale_files_updated = git.modified_files.select { |path| path.start_with?('locale') }
|
||||
# locale_files_updated.each do |locale_file_updated|
|
||||
# git_stats = git.info_for_file(locale_file_updated)
|
||||
# message "Git stats for #{locale_file_updated}: #{git_stats[:insertions]} insertions, #{git_stats[:deletions]} insertions"
|
||||
# end
|
||||
|
||||
if git.lines_of_code > 2_000
|
||||
warn "This merge request is definitely too big (#{git.lines_of_code} lines changed), please split it into multiple merge requests."
|
||||
elsif git.lines_of_code > 500
|
||||
warn "This merge request is quite big (#{git.lines_of_code} lines changed), please consider splitting it into multiple merge requests."
|
||||
end
|
|
@ -55,7 +55,7 @@ if gitlab.mr_labels.include?('database') || db_paths_to_review.any?
|
|||
markdown(DB_MESSAGE)
|
||||
markdown(DB_FILES_MESSAGE + helper.markdown_list(db_paths_to_review)) if db_paths_to_review.any?
|
||||
|
||||
unless helper.has_database_scoped_labels?(gitlab.mr_labels)
|
||||
unless helper.has_database_scoped_labels?
|
||||
gitlab.api.update_merge_request(gitlab.mr_json['project_id'],
|
||||
gitlab.mr_json['iid'],
|
||||
add_labels: 'database::review pending')
|
||||
|
|
|
@ -13,7 +13,7 @@ group: "%<group>s"
|
|||
SUGGEST_COMMENT
|
||||
|
||||
def check_feature_flag_yaml(feature_flag)
|
||||
mr_group_label = helper.group_label(gitlab.mr_labels)
|
||||
mr_group_label = helper.group_label
|
||||
|
||||
if feature_flag.group.nil?
|
||||
message_for_feature_flag_missing_group!(feature_flag: feature_flag, mr_group_label: mr_group_label)
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreatePartialCoveringIndexForPendingBuilds < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
EXISTING_INDEX = 'index_ci_builds_runner_id_pending'
|
||||
NEW_INDEX = 'index_ci_builds_runner_id_pending_covering'
|
||||
|
||||
def up
|
||||
execute "CREATE INDEX CONCURRENTLY #{NEW_INDEX} ON ci_builds (runner_id, id) INCLUDE (project_id) WHERE status = 'pending' AND type = 'Ci::Build'" unless index_exists_by_name?(:ci_builds, NEW_INDEX)
|
||||
|
||||
remove_concurrent_index_by_name :ci_builds, EXISTING_INDEX
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_index :ci_builds, :runner_id, where: "status = 'pending' AND type = 'Ci::Build'", name: EXISTING_INDEX
|
||||
remove_concurrent_index_by_name :ci_builds, NEW_INDEX
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
ccf7bce753adabfd7dd8a68fd49853514367f11af42879cae1b6aa28e4ebe94c
|
|
@ -22389,7 +22389,7 @@ CREATE INDEX index_ci_builds_on_user_id_and_created_at_and_type_eq_ci_build ON c
|
|||
|
||||
CREATE INDEX index_ci_builds_project_id_and_status_for_live_jobs_partial2 ON ci_builds USING btree (project_id, status) WHERE (((type)::text = 'Ci::Build'::text) AND ((status)::text = ANY (ARRAY[('running'::character varying)::text, ('pending'::character varying)::text, ('created'::character varying)::text])));
|
||||
|
||||
CREATE INDEX index_ci_builds_runner_id_pending ON ci_builds USING btree (runner_id) WHERE (((status)::text = 'pending'::text) AND ((type)::text = 'Ci::Build'::text));
|
||||
CREATE INDEX index_ci_builds_runner_id_pending_covering ON ci_builds USING btree (runner_id, id) INCLUDE (project_id) WHERE (((status)::text = 'pending'::text) AND ((type)::text = 'Ci::Build'::text));
|
||||
|
||||
CREATE INDEX index_ci_builds_runner_id_running ON ci_builds USING btree (runner_id) WHERE (((status)::text = 'running'::text) AND ((type)::text = 'Ci::Build'::text));
|
||||
|
||||
|
|
|
@ -127,6 +127,7 @@ Example response:
|
|||
"avatar_url" : null,
|
||||
"username" : "root"
|
||||
},
|
||||
"type" : "ISSUE",
|
||||
"updated_at" : "2016-01-04T15:31:51.081Z",
|
||||
"closed_at" : null,
|
||||
"closed_by" : null,
|
||||
|
@ -331,6 +332,7 @@ Example response:
|
|||
"id" : 9,
|
||||
"name" : "Dr. Luella Kovacek"
|
||||
},
|
||||
"type" : "ISSUE",
|
||||
"labels" : ["foo", "bar"],
|
||||
"upvotes": 4,
|
||||
"downvotes": 0,
|
||||
|
@ -531,6 +533,7 @@ Example response:
|
|||
"id" : 9,
|
||||
"name" : "Dr. Luella Kovacek"
|
||||
},
|
||||
"type" : "ISSUE",
|
||||
"labels" : ["foo", "bar"],
|
||||
"upvotes": 4,
|
||||
"downvotes": 0,
|
||||
|
@ -699,6 +702,7 @@ Example response:
|
|||
"id": 9,
|
||||
"name": "Dr. Luella Kovacek"
|
||||
},
|
||||
"type": "ISSUE",
|
||||
"labels": [],
|
||||
"upvotes": 4,
|
||||
"downvotes": 0,
|
||||
|
@ -863,6 +867,7 @@ Example response:
|
|||
"id" : 9,
|
||||
"name" : "Dr. Luella Kovacek"
|
||||
},
|
||||
"type" : "ISSUE",
|
||||
"labels" : [],
|
||||
"upvotes": 4,
|
||||
"downvotes": 0,
|
||||
|
@ -1002,6 +1007,7 @@ Example response:
|
|||
"state" : "opened",
|
||||
"assignees" : [],
|
||||
"assignee" : null,
|
||||
"type" : "ISSUE",
|
||||
"labels" : [
|
||||
"bug"
|
||||
],
|
||||
|
@ -1375,6 +1381,7 @@ Example response:
|
|||
"avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
|
||||
"web_url": "https://gitlab.example.com/axel.block"
|
||||
},
|
||||
"type" : "ISSUE",
|
||||
"author": {
|
||||
"name": "Kris Steuber",
|
||||
"username": "solon.cremin",
|
||||
|
@ -1518,6 +1525,7 @@ Example response:
|
|||
"avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
|
||||
"web_url": "https://gitlab.example.com/axel.block"
|
||||
},
|
||||
"type" : "ISSUE",
|
||||
"author": {
|
||||
"name": "Kris Steuber",
|
||||
"username": "solon.cremin",
|
||||
|
@ -1651,6 +1659,7 @@ Example response:
|
|||
"avatar_url": "http://www.gravatar.com/avatar/3e6f06a86cf27fa8b56f3f74f7615987?s=80&d=identicon",
|
||||
"web_url": "https://gitlab.example.com/keyon"
|
||||
},
|
||||
"type" : "ISSUE",
|
||||
"closed_at": null,
|
||||
"closed_by": null,
|
||||
"author": {
|
||||
|
@ -1756,6 +1765,7 @@ Example response:
|
|||
"avatar_url": "http://www.gravatar.com/avatar/a7fa515d53450023c83d62986d0658a8?s=80&d=identicon",
|
||||
"web_url": "https://gitlab.example.com/francisca"
|
||||
},
|
||||
"type" : "ISSUE",
|
||||
"author": {
|
||||
"name": "Maxie Medhurst",
|
||||
"username": "craig_rutherford",
|
||||
|
|
|
@ -226,13 +226,15 @@ If your rules match both branch pipelines and merge request pipelines,
|
|||
#### `workflow:rules:variables`
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294232) in GitLab 13.11.
|
||||
> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
|
||||
> - It's disabled on GitLab.com.
|
||||
> - It's not recommended for production use.
|
||||
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-workflowrulesvariables). **(CORE ONLY)**
|
||||
> - [Deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
|
||||
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300997) in GitLab 13.12.
|
||||
> - Enabled on GitLab.com.
|
||||
> - Recommended for production use.
|
||||
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-workflowrulesvariables). **(FREE SELF)**
|
||||
|
||||
WARNING:
|
||||
This feature might not be available to you. Check the **version history** note above for details.
|
||||
There can be
|
||||
[risks when disabling released features](../../user/feature_flags.md#risks-when-disabling-released-features).
|
||||
Refer to this feature's version history for more details.
|
||||
|
||||
You can use [`variables`](#variables) in `workflow:rules:` to define variables for specific pipeline conditions.
|
||||
|
||||
|
@ -285,12 +287,12 @@ When the branch is something else:
|
|||
- job1's `DEPLOY_VARIABLE` is `job1-default-deploy`.
|
||||
- job2's `DEPLOY_VARIABLE` is `default-deploy`.
|
||||
|
||||
##### Enable or disable workflow:rules:variables **(CORE ONLY)**
|
||||
##### Enable or disable workflow:rules:variables **(FREE SELF)**
|
||||
|
||||
rules:variables is under development and not ready for production use.
|
||||
It is deployed behind a feature flag that is **disabled by default**.
|
||||
workflow:rules:variables is under development but ready for production use.
|
||||
It is deployed behind a feature flag that is **enabled by default**.
|
||||
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
|
||||
can enable it.
|
||||
can opt to disable it.
|
||||
|
||||
To enable it:
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
stage: none
|
||||
group: unassigned
|
||||
info: https://gitlab.com/gitlab-jh/gitlab
|
||||
---
|
||||
|
||||
# Guidelines for reviewing JiHu (JH) Edition related merge requests
|
||||
|
||||
We have two kinds of changes related to JH:
|
||||
|
||||
- Inside `jh/`
|
||||
- This is beyond EE repository and not the intention for this documentation.
|
||||
- Outside `jh/`
|
||||
- These will have to sit in EE repository, so reviewers and maintainers for
|
||||
EE repository will have to review and maintain. This includes codes like
|
||||
`Gitlab.jh?`, and how it attempts to load codes under `jh/` just like we
|
||||
have codes which will load codes under `ee/`.
|
||||
- This documentation intended to guide how those codes should look like, so
|
||||
we'll have better understanding what are the changes needed for looking up
|
||||
codes under `jh/`.
|
||||
- We will generalize this so both EE and JH can share the same mechanism,
|
||||
then we wouldn't have to treat them differently.
|
||||
|
||||
If needed, review the corresponding JH merge request located at [JH repository](https://gitlab.com/gitlab-jh/gitlab)
|
||||
|
||||
## Act as EE when `jh/` does not exist
|
||||
|
||||
- In the case of EE repository, `jh/` does not exist so it should just act like EE (or CE when the license is absent)
|
||||
- In the case of JH repository, `jh/` does exist but `EE_ONLY` environment variable can be set to force it run under EE mode.
|
||||
- In the case of JH repository, `jh/` does exist but `FOSS_ONLY` environment variable can be set to force it run under CE mode.
|
||||
|
||||
## CI pipelines in a JH context
|
||||
|
||||
EE repository does not have `jh/` directory therefore there is no way to run
|
||||
JH pipelines in the EE repository. All JH tests should go to [JH repository](https://gitlab.com/gitlab-jh/gitlab).
|
||||
|
||||
The top-level JH CI configuration is located at `jh/.gitlab-ci.yml` (which
|
||||
does not exist in EE repository) and it'll include EE CI configurations
|
||||
accordingly. Sometimes it's needed to update the EE CI configurations for JH
|
||||
to customize more easily.
|
||||
|
||||
### JH features based on CE or EE features
|
||||
|
||||
For features that build on existing CE/EE features, a module in the `JH`
|
||||
namespace injected in the CE/EE class/module is needed. This aligns with
|
||||
what we're doing with EE features.
|
||||
|
||||
See [EE features based on CE features](ee_features.md#ee-features-based-on-ce-features) for more details.
|
||||
|
||||
For example, to prepend a module into the `User` class you would use
|
||||
the following approach:
|
||||
|
||||
```ruby
|
||||
class User < ActiveRecord::Base
|
||||
# ... lots of code here ...
|
||||
end
|
||||
|
||||
User.prepend_mod
|
||||
```
|
||||
|
||||
Under EE, `User.prepend_mod` will attempt to:
|
||||
|
||||
- Load EE module
|
||||
|
||||
Under JH, `User.prepend_mod` will attempt to:
|
||||
|
||||
- Load EE module, and:
|
||||
- Load JH module
|
||||
|
||||
Do not use methods such as `prepend`, `extend`, and `include`. Instead, use
|
||||
`prepend_mod`, `extend_mod`, or `include_mod`. These methods will try to find
|
||||
the relevant EE and JH modules by the name of the receiver module.
|
||||
|
||||
If reviewing the corresponding JH file is needed, it should be found at
|
||||
[JH repository](https://gitlab.com/gitlab-jh/gitlab).
|
||||
|
||||
### General guidance for writing JH extensions
|
||||
|
||||
See [Guidelines for implementing Enterprise Edition features](ee_features.md)
|
||||
for general guidance.
|
|
@ -122,21 +122,16 @@ older format is still supported, allowing existing aliases or contacts to contin
|
|||
|
||||
To link directly to the new issue page with prefilled fields, use query
|
||||
string parameters in a URL. You can embed a URL in an external
|
||||
HTML page, or create issues with certain
|
||||
HTML page to create issues with certain
|
||||
fields prefilled.
|
||||
|
||||
The title, description, description template, and confidential fields can be prefilled
|
||||
using this method. You cannot pre-fill both the description and description template
|
||||
fields in the same URL because a description template also populates the description
|
||||
field.
|
||||
|
||||
| Field | URL Parameter Name | Notes |
|
||||
|----------------------|-----------------------|-------------------------------------------------------|
|
||||
| title | `issue[title]` | |
|
||||
| description | `issue[description]` | |
|
||||
| description template | `issuable_template` | |
|
||||
| issue type | `issue[issue_type]` | Either `incident` or `issue` |
|
||||
| confidential | `issue[confidential]` | Parameter value must be `true` to set to confidential |
|
||||
| description | `issue[description]` | Cannot be used at the same time as `issuable_template`. |
|
||||
| description template | `issuable_template` | Cannot be used at the same time as `issue[description]`. |
|
||||
| issue type | `issue[issue_type]` | Either `incident` or `issue`. |
|
||||
| confidential | `issue[confidential]` | Parameter value must be `true` to set to confidential. |
|
||||
|
||||
Follow these examples to form your new issue URL with prefilled fields.
|
||||
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
module API
|
||||
module Entities
|
||||
class IssueBasic < IssuableEntity
|
||||
format_with(:upcase) do |item|
|
||||
item.upcase if item.respond_to?(:upcase)
|
||||
end
|
||||
|
||||
expose :closed_at
|
||||
expose :closed_by, using: Entities::UserBasic
|
||||
|
||||
|
@ -16,6 +20,10 @@ module API
|
|||
|
||||
expose :milestone, using: Entities::Milestone
|
||||
expose :assignees, :author, using: Entities::UserBasic
|
||||
expose :issue_type,
|
||||
as: :type,
|
||||
format_with: :upcase,
|
||||
documentation: { type: "String", desc: "One of #{Issue.issue_types.keys.map(&:upcase)}" }
|
||||
|
||||
expose :assignee, using: ::API::Entities::UserBasic do |issue|
|
||||
issue.assignees.first
|
||||
|
|
|
@ -92,6 +92,16 @@ module Gitlab
|
|||
Rails.env.development? || Rails.env.test?
|
||||
end
|
||||
|
||||
def self.extensions
|
||||
if jh?
|
||||
%w[ee jh]
|
||||
elsif ee?
|
||||
%w[ee]
|
||||
else
|
||||
%w[]
|
||||
end
|
||||
end
|
||||
|
||||
def self.ee?
|
||||
@is_ee ||=
|
||||
# We use this method when the Rails environment is not loaded. This
|
||||
|
|
|
@ -11,7 +11,16 @@ module Gitlab
|
|||
|
||||
def perform!
|
||||
if skipped?
|
||||
@pipeline.skip if @command.save_incompleted
|
||||
if @command.save_incompleted
|
||||
if Feature.enabled?(:ci_pipeline_ensure_iid_on_skip, @pipeline.project, default_enabled: :yaml)
|
||||
# Project iid must be called outside a transaction, so we ensure it is set here
|
||||
# otherwise it may be set within the state transition transaction of the skip call
|
||||
# which it will lock the InternalId row for the whole transaction
|
||||
@pipeline.ensure_project_iid!
|
||||
end
|
||||
|
||||
@pipeline.skip
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Ci
|
||||
module Pipeline
|
||||
module Chain
|
||||
module Validate
|
||||
class SecurityOrchestrationPolicy < Chain::Base
|
||||
include Chain::Helpers
|
||||
|
||||
def perform!
|
||||
# no-op
|
||||
end
|
||||
|
||||
def break?
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Gitlab::Ci::Pipeline::Chain::Validate::SecurityOrchestrationPolicy.prepend_if_ee('EE::Gitlab::Ci::Pipeline::Chain::Validate::SecurityOrchestrationPolicy')
|
|
@ -99,11 +99,19 @@ module Gitlab
|
|||
def group_config_file
|
||||
Rails.root.join('lib/gitlab/import_export/group/import_export.yml')
|
||||
end
|
||||
|
||||
def group_wiki_repo_bundle_filename(group_id)
|
||||
"#{group_id}.wiki.bundle"
|
||||
end
|
||||
|
||||
def group_wiki_repo_bundle_path(shared, filename)
|
||||
File.join(shared.export_path, 'repositories', filename)
|
||||
end
|
||||
|
||||
def group_wiki_repo_bundle_full_path(shared, group_id)
|
||||
group_wiki_repo_bundle_path(shared, group_wiki_repo_bundle_filename(group_id))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Gitlab::ImportExport.prepend_if_ee('EE::Gitlab::ImportExport')
|
||||
|
||||
# The methods in `Gitlab::ImportExport::GroupHelper` should be available as both
|
||||
# instance and class methods.
|
||||
Gitlab::ImportExport.extend_if_ee('Gitlab::ImportExport::GroupHelper')
|
||||
Gitlab::ImportExport.prepend_mod
|
||||
|
|
|
@ -12,5 +12,5 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
Gitlab::SubscriptionPortal.prepend_if_jh('JH::Gitlab::SubscriptionPortal')
|
||||
Gitlab::SubscriptionPortal.prepend_mod
|
||||
Gitlab::SubscriptionPortal::SUBSCRIPTIONS_URL = Gitlab::SubscriptionPortal.subscriptions_url.freeze
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module Projects
|
||||
module Menus
|
||||
class AnalyticsMenu < ::Sidebars::Menu
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
override :configure_menu_items
|
||||
def configure_menu_items
|
||||
return false unless can?(context.current_user, :read_analytics, context.project)
|
||||
|
||||
add_item(ci_cd_analytics_menu_item)
|
||||
add_item(repository_analytics_menu_item)
|
||||
add_item(cycle_analytics_menu_item)
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
override :link
|
||||
def link
|
||||
return cycle_analytics_menu_item.link if cycle_analytics_menu_item
|
||||
|
||||
items.first.link
|
||||
end
|
||||
|
||||
override :extra_container_html_options
|
||||
def extra_container_html_options
|
||||
{
|
||||
class: 'shortcuts-analytics'
|
||||
}
|
||||
end
|
||||
|
||||
override :title
|
||||
def title
|
||||
_('Analytics')
|
||||
end
|
||||
|
||||
override :sprite_icon
|
||||
def sprite_icon
|
||||
'chart'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ci_cd_analytics_menu_item
|
||||
return if context.project.empty_repo?
|
||||
return unless context.project.feature_available?(:builds, context.current_user)
|
||||
return unless can?(context.current_user, :read_build, context.project)
|
||||
|
||||
::Sidebars::MenuItem.new(
|
||||
title: _('CI/CD'),
|
||||
link: charts_project_pipelines_path(context.project),
|
||||
active_routes: { path: 'pipelines#charts' },
|
||||
item_id: :ci_cd_analytics
|
||||
)
|
||||
end
|
||||
|
||||
def repository_analytics_menu_item
|
||||
return if context.project.empty_repo?
|
||||
|
||||
::Sidebars::MenuItem.new(
|
||||
title: _('Repository'),
|
||||
link: charts_project_graph_path(context.project, context.current_ref),
|
||||
container_html_options: { class: 'shortcuts-repository-charts' },
|
||||
active_routes: { path: 'graphs#charts' },
|
||||
item_id: :repository_analytics
|
||||
)
|
||||
end
|
||||
|
||||
def cycle_analytics_menu_item
|
||||
strong_memoize(:cycle_analytics_menu_item) do
|
||||
next unless can?(context.current_user, :read_cycle_analytics, context.project)
|
||||
|
||||
::Sidebars::MenuItem.new(
|
||||
title: _('Value Stream'),
|
||||
link: project_cycle_analytics_path(context.project),
|
||||
container_html_options: { class: 'shortcuts-project-cycle-analytics' },
|
||||
active_routes: { path: 'cycle_analytics#show' },
|
||||
item_id: :cycle_analytics
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Sidebars::Projects::Menus::AnalyticsMenu.prepend_if_ee('EE::Sidebars::Projects::Menus::AnalyticsMenu')
|
|
@ -18,6 +18,7 @@ module Sidebars
|
|||
add_menu(Sidebars::Projects::Menus::SecurityComplianceMenu.new(context))
|
||||
add_menu(Sidebars::Projects::Menus::OperationsMenu.new(context))
|
||||
add_menu(Sidebars::Projects::Menus::PackagesRegistriesMenu.new(context))
|
||||
add_menu(Sidebars::Projects::Menus::AnalyticsMenu.new(context))
|
||||
end
|
||||
|
||||
override :render_raw_menus_partial
|
||||
|
|
|
@ -6689,6 +6689,9 @@ msgstr ""
|
|||
msgid "CloudLicense|Buy subscription"
|
||||
msgstr ""
|
||||
|
||||
msgid "CloudLicense|Enter activation code"
|
||||
msgstr ""
|
||||
|
||||
msgid "CloudLicense|Free trial"
|
||||
msgstr ""
|
||||
|
||||
|
@ -6698,9 +6701,6 @@ msgstr ""
|
|||
msgid "CloudLicense|I agree that my use of the GitLab Software is subject to the Subscription Agreement located at the %{linkStart}Terms of Service%{linkEnd}, unless otherwise agreed to in writing with GitLab."
|
||||
msgstr ""
|
||||
|
||||
msgid "CloudLicense|Learn how to %{linkStart}activate your subscription%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "CloudLicense|Maximum users"
|
||||
msgstr ""
|
||||
|
||||
|
@ -12971,6 +12971,21 @@ msgstr ""
|
|||
msgid "Errors:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Escalation Policies"
|
||||
msgstr ""
|
||||
|
||||
msgid "Escalation policies"
|
||||
msgstr ""
|
||||
|
||||
msgid "EscalationPolicies|Add an escalation policy"
|
||||
msgstr ""
|
||||
|
||||
msgid "EscalationPolicies|Create an escalation policy in GitLab"
|
||||
msgstr ""
|
||||
|
||||
msgid "EscalationPolicies|Set up escalation policies to define who is paged, and when, in the event the first users paged don't respond."
|
||||
msgstr ""
|
||||
|
||||
msgid "Estimate"
|
||||
msgstr ""
|
||||
|
||||
|
@ -16486,6 +16501,9 @@ msgstr ""
|
|||
msgid "If you want to re-enable two-factor authentication, visit the %{settings_link_to} page."
|
||||
msgstr ""
|
||||
|
||||
msgid "If you've purchased or renewed your subscription and have an activation code, please enter it below to start the activation process."
|
||||
msgstr ""
|
||||
|
||||
msgid "If your HTTP repository is not publicly accessible, add your credentials."
|
||||
msgstr ""
|
||||
|
||||
|
@ -31070,6 +31088,9 @@ msgstr ""
|
|||
msgid "SuperSonics|Last Sync"
|
||||
msgstr ""
|
||||
|
||||
msgid "SuperSonics|Learn how to %{linkStart}activate your subscription%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "SuperSonics|Licensed to"
|
||||
msgstr ""
|
||||
|
||||
|
@ -32267,9 +32288,6 @@ msgstr ""
|
|||
msgid "There are running deployments on the environment. Please retry later."
|
||||
msgstr ""
|
||||
|
||||
msgid "There is a connectivity issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "There is a halted Elasticsearch migration"
|
||||
msgstr ""
|
||||
|
||||
|
@ -38715,6 +38733,12 @@ msgstr ""
|
|||
msgid "satisfied"
|
||||
msgstr ""
|
||||
|
||||
msgid "scan-execution-policy: policy not applied, %{policy_path} file is invalid"
|
||||
msgstr ""
|
||||
|
||||
msgid "scan-execution-policy: policy not applied, %{policy_path} file is missing"
|
||||
msgstr ""
|
||||
|
||||
msgid "security Reports|There was an error creating the merge request"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -107,4 +107,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Admin::Menu.prepend_if_ee('QA::EE::Page::Admin::Menu')
|
||||
QA::Page::Admin::Menu.prepend_if_ee('Page::Admin::Menu', namespace: QA)
|
||||
|
|
|
@ -20,4 +20,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Admin::Overview::Groups::Edit.prepend_if_ee('QA::EE::Page::Admin::Overview::Groups::Edit')
|
||||
QA::Page::Admin::Overview::Groups::Edit.prepend_if_ee('Page::Admin::Overview::Groups::Edit', namespace: QA)
|
||||
|
|
|
@ -137,4 +137,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Component::IssueBoard::Show.prepend_if_ee('QA::EE::Page::Component::IssueBoard::Show')
|
||||
QA::Page::Component::IssueBoard::Show.prepend_if_ee('Page::Component::IssueBoard::Show', namespace: QA)
|
||||
|
|
|
@ -45,4 +45,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Dashboard::Projects.prepend_if_ee('QA::EE::Page::Dashboard::Projects')
|
||||
QA::Page::Dashboard::Projects.prepend_if_ee('Page::Dashboard::Projects', namespace: QA)
|
||||
|
|
|
@ -62,4 +62,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::File::Show.prepend_if_ee('QA::EE::Page::File::Show')
|
||||
QA::Page::File::Show.prepend_if_ee('Page::File::Show', namespace: QA)
|
||||
|
|
|
@ -83,4 +83,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Group::Menu.prepend_if_ee('QA::EE::Page::Group::Menu')
|
||||
QA::Page::Group::Menu.prepend_if_ee('Page::Group::Menu', namespace: QA)
|
||||
|
|
|
@ -129,4 +129,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Group::Settings::General.prepend_if_ee('QA::EE::Page::Group::Settings::General')
|
||||
QA::Page::Group::Settings::General.prepend_if_ee('Page::Group::Settings::General', namespace: QA)
|
||||
|
|
|
@ -175,4 +175,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Main::Menu.prepend_if_ee('QA::EE::Page::Main::Menu')
|
||||
QA::Page::Main::Menu.prepend_if_ee('Page::Main::Menu', namespace: QA)
|
||||
|
|
|
@ -41,4 +41,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::MergeRequest::New.prepend_if_ee('QA::EE::Page::MergeRequest::New')
|
||||
QA::Page::MergeRequest::New.prepend_if_ee('Page::MergeRequest::New', namespace: QA)
|
||||
|
|
|
@ -390,4 +390,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::MergeRequest::Show.prepend_if_ee('QA::EE::Page::MergeRequest::Show')
|
||||
QA::Page::MergeRequest::Show.prepend_if_ee('Page::MergeRequest::Show', namespace: QA)
|
||||
|
|
|
@ -30,4 +30,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Milestone::Show.prepend_if_ee('QA::EE::Page::Milestone::Show')
|
||||
QA::Page::Milestone::Show.prepend_if_ee('Page::Milestone::Show', namespace: QA)
|
||||
|
|
|
@ -56,4 +56,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Profile::Menu.prepend_if_ee('QA::EE::Page::Profile::Menu')
|
||||
QA::Page::Profile::Menu.prepend_if_ee('Page::Profile::Menu', namespace: QA)
|
||||
|
|
|
@ -85,4 +85,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Issue::Index.prepend_if_ee('QA::EE::Page::Project::Issue::Index')
|
||||
QA::Page::Project::Issue::Index.prepend_if_ee('Page::Project::Issue::Index', namespace: QA)
|
||||
|
|
|
@ -70,4 +70,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Issue::Show.prepend_if_ee('QA::EE::Page::Project::Issue::Show')
|
||||
QA::Page::Project::Issue::Show.prepend_if_ee('Page::Project::Issue::Show', namespace: QA)
|
||||
|
|
|
@ -75,4 +75,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Job::Show.prepend_if_ee('QA::EE::Page::Project::Job::Show')
|
||||
QA::Page::Project::Job::Show.prepend_if_ee('Page::Project::Job::Show', namespace: QA)
|
||||
|
|
|
@ -56,4 +56,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Menu.prepend_if_ee('QA::EE::Page::Project::Menu')
|
||||
QA::Page::Project::Menu.prepend_if_ee('Page::Project::Menu', namespace: QA)
|
||||
|
|
|
@ -72,4 +72,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::New.prepend_if_ee('QA::EE::Page::Project::New')
|
||||
QA::Page::Project::New.prepend_if_ee('Page::Project::New', namespace: QA)
|
||||
|
|
|
@ -134,4 +134,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Operations::Metrics::Show.prepend_if_ee('QA::EE::Page::Project::Operations::Metrics::Show')
|
||||
QA::Page::Project::Operations::Metrics::Show.prepend_if_ee('Page::Project::Operations::Metrics::Show', namespace: QA)
|
||||
|
|
|
@ -27,4 +27,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Packages::Index.prepend_if_ee('QA::EE::Page::Project::Packages::Index')
|
||||
QA::Page::Project::Packages::Index.prepend_if_ee('Page::Project::Packages::Index', namespace: QA)
|
||||
|
|
|
@ -67,4 +67,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Pipeline::Index.prepend_if_ee('QA::EE::Page::Project::Pipeline::Index')
|
||||
QA::Page::Project::Pipeline::Index.prepend_if_ee('Page::Project::Pipeline::Index', namespace: QA)
|
||||
|
|
|
@ -117,4 +117,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Pipeline::Show.prepend_if_ee('QA::EE::Page::Project::Pipeline::Show')
|
||||
QA::Page::Project::Pipeline::Show.prepend_if_ee('Page::Project::Pipeline::Show', namespace: QA)
|
||||
|
|
|
@ -43,4 +43,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Settings::CICD.prepend_if_ee("QA::EE::Page::Project::Settings::CICD")
|
||||
QA::Page::Project::Settings::CICD.prepend_if_ee("Page::Project::Settings::CICD", namespace: QA)
|
||||
|
|
|
@ -23,4 +23,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Settings::Integrations.prepend_if_ee('QA::EE::Page::Project::Settings::Integrations')
|
||||
QA::Page::Project::Settings::Integrations.prepend_if_ee('Page::Project::Settings::Integrations', namespace: QA)
|
||||
|
|
|
@ -57,4 +57,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Settings::Main.prepend_if_ee("QA::EE::Page::Project::Settings::Main")
|
||||
QA::Page::Project::Settings::Main.prepend_if_ee("Page::Project::Settings::Main", namespace: QA)
|
||||
|
|
|
@ -38,4 +38,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Settings::MergeRequest.prepend_if_ee("QA::EE::Page::Project::Settings::MergeRequest")
|
||||
QA::Page::Project::Settings::MergeRequest.prepend_if_ee("Page::Project::Settings::MergeRequest", namespace: QA)
|
||||
|
|
|
@ -129,4 +129,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Settings::MirroringRepositories.prepend_if_ee('QA::EE::Page::Project::Settings::MirroringRepositories')
|
||||
QA::Page::Project::Settings::MirroringRepositories.prepend_if_ee('Page::Project::Settings::MirroringRepositories', namespace: QA)
|
||||
|
|
|
@ -69,4 +69,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Settings::ProtectedBranches.prepend_if_ee('QA::EE::Page::Project::Settings::ProtectedBranches')
|
||||
QA::Page::Project::Settings::ProtectedBranches.prepend_if_ee('Page::Project::Settings::ProtectedBranches', namespace: QA)
|
||||
|
|
|
@ -43,4 +43,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Settings::ProtectedTags.prepend_if_ee('QA::EE::Page::Project::Settings::ProtectedTags')
|
||||
QA::Page::Project::Settings::ProtectedTags.prepend_if_ee('Page::Project::Settings::ProtectedTags', namespace: QA)
|
||||
|
|
|
@ -62,4 +62,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Settings::Repository.prepend_if_ee('QA::EE::Page::Project::Settings::Repository')
|
||||
QA::Page::Project::Settings::Repository.prepend_if_ee('Page::Project::Settings::Repository', namespace: QA)
|
||||
|
|
|
@ -180,4 +180,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Show.prepend_if_ee('QA::EE::Page::Project::Show')
|
||||
QA::Page::Project::Show.prepend_if_ee('Page::Project::Show', namespace: QA)
|
||||
|
|
|
@ -26,4 +26,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Snippet::Index.prepend_if_ee('QA::EE::Page::Project::Snippet::Index')
|
||||
QA::Page::Project::Snippet::Index.prepend_if_ee('Page::Project::Snippet::Index', namespace: QA)
|
||||
|
|
|
@ -311,4 +311,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::WebIDE::Edit.prepend_if_ee('QA::EE::Page::Component::WebIDE::WebTerminalPanel')
|
||||
QA::Page::Project::WebIDE::Edit.prepend_if_ee('Page::Component::WebIDE::WebTerminalPanel', namespace: QA)
|
||||
|
|
|
@ -14,4 +14,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Wiki::Show.prepend_if_ee('QA::EE::Page::Project::Wiki::Show')
|
||||
QA::Page::Project::Wiki::Show.prepend_if_ee('Page::Project::Wiki::Show', namespace: QA)
|
||||
|
|
|
@ -21,4 +21,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Page::Registration::Welcome.prepend_if_ee('QA::EE::Page::Registration::Welcome')
|
||||
QA::Page::Registration::Welcome.prepend_if_ee('Page::Registration::Welcome', namespace: QA)
|
||||
|
|
|
@ -403,4 +403,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Runtime::Env.extend_if_ee('QA::EE::Runtime::Env')
|
||||
QA::Runtime::Env.extend_if_ee('Runtime::Env', namespace: QA)
|
||||
|
|
|
@ -58,4 +58,4 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
QA::Scenario::Test::Sanity::Selectors.prepend_if_ee('QA::EE::Scenario::Test::Sanity::Selectors')
|
||||
QA::Scenario::Test::Sanity::Selectors.prepend_if_ee('Scenario::Test::Sanity::Selectors', namespace: QA)
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rubygems'
|
||||
require 'fog/aws'
|
||||
|
||||
class SyncReports
|
||||
ACTIONS = %w[get put].freeze
|
||||
|
||||
attr_reader :options
|
||||
|
||||
def initialize(options)
|
||||
@options = options
|
||||
|
||||
perform_sync!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def perform_sync!
|
||||
case options[:action]
|
||||
when 'get'
|
||||
get_reports!
|
||||
when 'put'
|
||||
put_reports!
|
||||
end
|
||||
end
|
||||
|
||||
def get_reports!
|
||||
options[:report_paths].each { |report_path| get_report!(report_path) }
|
||||
end
|
||||
|
||||
def put_reports!
|
||||
options[:report_paths].each { |report_path| put_report!(report_path) }
|
||||
end
|
||||
|
||||
def get_report!(report_path)
|
||||
file = bucket.files.get(report_path)
|
||||
|
||||
if file.respond_to?(:body)
|
||||
File.write(report_path, file.body)
|
||||
puts "#{report_path} was retrieved from S3."
|
||||
else
|
||||
puts "#{report_path} does not seem to exist on S3."
|
||||
end
|
||||
end
|
||||
|
||||
def put_report!(report_path)
|
||||
bucket.files.create(
|
||||
key: report_path,
|
||||
body: File.open(report_path),
|
||||
public: true
|
||||
)
|
||||
puts "#{report_path} was uploaded to S3."
|
||||
end
|
||||
|
||||
def bucket
|
||||
@bucket ||= storage.directories.get(options[:bucket])
|
||||
end
|
||||
|
||||
def storage
|
||||
@storage ||=
|
||||
Fog::Storage.new(
|
||||
provider: 'AWS',
|
||||
aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
|
||||
aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def usage!(error: 'action')
|
||||
print "\n[ERROR]: "
|
||||
case error
|
||||
when 'action'
|
||||
puts "Please specify an action as first argument: #{SyncReports::ACTIONS.join(', ')}\n\n"
|
||||
when 'bucket'
|
||||
puts "Please specify a bucket as second argument!\n\n"
|
||||
when 'files'
|
||||
puts "Please specify one or more file paths as third argument!\n\n"
|
||||
end
|
||||
puts "Usage: #{__FILE__} [get|put] bucket report_path ...\n\n"
|
||||
puts "Note: the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment "\
|
||||
"variables need to be set\n\n"
|
||||
exit 1
|
||||
end
|
||||
|
||||
if $0 == __FILE__
|
||||
action = ARGV.shift
|
||||
usage!(error: 'action') unless SyncReports::ACTIONS.include?(action)
|
||||
|
||||
bucket = ARGV.shift
|
||||
usage!(error: 'bucket') unless bucket
|
||||
usage!(error: 'files') unless ARGV.any?
|
||||
|
||||
SyncReports.new(action: action, bucket: bucket, report_paths: ARGV)
|
||||
end
|
|
@ -0,0 +1,141 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'fast_spec_helper'
|
||||
|
||||
RSpec.describe InjectEnterpriseEditionModule do
|
||||
let(:extension_name) { 'FF' }
|
||||
let(:extension_namespace) { Module.new }
|
||||
let(:fish_name) { 'Fish' }
|
||||
let(:fish_class) { Class.new }
|
||||
let(:fish_extension) { Module.new }
|
||||
|
||||
before do
|
||||
# Make sure we're not relying on which mode we're running under
|
||||
allow(Gitlab).to receive(:extensions).and_return([extension_name.downcase])
|
||||
|
||||
# Test on an imagined extension and imagined class
|
||||
stub_const(fish_name, fish_class) # Fish
|
||||
allow(fish_class).to receive(:name).and_return(fish_name)
|
||||
end
|
||||
|
||||
shared_examples 'expand the extension with' do |method|
|
||||
context 'when extension namespace is set at top-level' do
|
||||
before do
|
||||
stub_const(extension_name, extension_namespace) # FF
|
||||
extension_namespace.const_set(fish_name, fish_extension) # FF::Fish
|
||||
end
|
||||
|
||||
it "calls #{method} with the extension module" do
|
||||
expect(fish_class).to receive(method).with(fish_extension)
|
||||
|
||||
fish_class.__send__("#{method}_if_ee", fish_name)
|
||||
end
|
||||
|
||||
it "ignores EE prefix and calls #{method} with the extension module" do
|
||||
expect(fish_class).to receive(method).with(fish_extension)
|
||||
|
||||
fish_class.__send__("#{method}_if_ee", "EE::#{fish_name}")
|
||||
end
|
||||
|
||||
it "ignores ::EE prefix and calls #{method} with the extension module" do
|
||||
expect(fish_class).to receive(method).with(fish_extension)
|
||||
|
||||
fish_class.__send__("#{method}_if_ee", "::EE::#{fish_name}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when extension namespace is set at another namespace' do
|
||||
let(:another_namespace) { Module.new } # QA
|
||||
|
||||
before do
|
||||
another_namespace.const_set(extension_name, extension_namespace) # QA::FF
|
||||
extension_namespace.const_set(fish_name, fish_extension) # QA::FF::Fish
|
||||
end
|
||||
|
||||
it "calls #{method} with the extension module from the additional namespace" do
|
||||
expect(fish_class).to receive(method).with(fish_extension)
|
||||
|
||||
fish_class.__send__("#{method}_if_ee", fish_name, namespace: another_namespace)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when extension namespace exists but not the extension' do
|
||||
before do
|
||||
stub_const(extension_name, extension_namespace) # FF
|
||||
end
|
||||
|
||||
it "does not call #{method}" do
|
||||
expect(fish_class).not_to receive(method).with(fish_extension)
|
||||
|
||||
fish_class.__send__("#{method}_if_ee", fish_name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when extension namespace does not exist' do
|
||||
it "does not call #{method}" do
|
||||
expect(fish_class).not_to receive(method).with(fish_extension)
|
||||
|
||||
fish_class.__send__("#{method}_if_ee", fish_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'expand the assumed extension with' do |method|
|
||||
context 'when extension namespace is set at top-level' do
|
||||
before do
|
||||
stub_const(extension_name, extension_namespace) # FF
|
||||
extension_namespace.const_set(fish_name, fish_extension) # FF::Fish
|
||||
end
|
||||
|
||||
it "calls #{method} with the extension module" do
|
||||
expect(fish_class).to receive(method).with(fish_extension)
|
||||
|
||||
fish_class.__send__("#{method}_mod")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when extension namespace exists but not the extension' do
|
||||
before do
|
||||
stub_const(extension_name, extension_namespace) # FF
|
||||
end
|
||||
|
||||
it "does not call #{method}" do
|
||||
expect(fish_class).not_to receive(method).with(fish_extension)
|
||||
|
||||
fish_class.__send__("#{method}_mod")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when extension namespace does not exist' do
|
||||
it "does not call #{method}" do
|
||||
expect(fish_class).not_to receive(method).with(fish_extension)
|
||||
|
||||
fish_class.__send__("#{method}_mod")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#prepend_if_ee' do
|
||||
it_behaves_like 'expand the extension with', :prepend
|
||||
end
|
||||
|
||||
describe '#extend_if_ee' do
|
||||
it_behaves_like 'expand the extension with', :extend
|
||||
end
|
||||
|
||||
describe '#include_if_ee' do
|
||||
it_behaves_like 'expand the extension with', :include
|
||||
end
|
||||
|
||||
describe '#prepend_mod' do
|
||||
it_behaves_like 'expand the assumed extension with', :prepend
|
||||
end
|
||||
|
||||
describe '#extend_mod' do
|
||||
it_behaves_like 'expand the assumed extension with', :extend
|
||||
end
|
||||
|
||||
describe '#include_mod' do
|
||||
it_behaves_like 'expand the assumed extension with', :include
|
||||
end
|
||||
end
|
|
@ -5,17 +5,14 @@ require 'spec_helper'
|
|||
RSpec.describe 'Issue Sidebar' do
|
||||
include MobileHelpers
|
||||
|
||||
let(:group) { create(:group, :nested) }
|
||||
let(:project) { create(:project, :public, namespace: group) }
|
||||
let!(:user) { create(:user) }
|
||||
let!(:label) { create(:label, project: project, title: 'bug') }
|
||||
let(:issue) { create(:labeled_issue, project: project, labels: [label]) }
|
||||
let!(:xss_label) { create(:label, project: project, title: '<script>alert("xss");</script>') }
|
||||
let!(:milestone_expired) { create(:milestone, project: project, due_date: 5.days.ago) }
|
||||
let!(:milestone_no_duedate) { create(:milestone, project: project, title: 'Foo - No due date') }
|
||||
let!(:milestone1) { create(:milestone, project: project, title: 'Milestone-1', due_date: 20.days.from_now) }
|
||||
let!(:milestone2) { create(:milestone, project: project, title: 'Milestone-2', due_date: 15.days.from_now) }
|
||||
let!(:milestone3) { create(:milestone, project: project, title: 'Milestone-3', due_date: 10.days.from_now) }
|
||||
let_it_be(:group) { create(:group, :nested) }
|
||||
let_it_be(:project) { create(:project, :public, namespace: group) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:label) { create(:label, project: project, title: 'bug') }
|
||||
let_it_be(:issue) { create(:labeled_issue, project: project, labels: [label]) }
|
||||
let_it_be(:mock_date) { Date.today.at_beginning_of_month + 2.days }
|
||||
let_it_be(:issue_with_due_date) { create(:issue, project: project, due_date: mock_date) }
|
||||
let_it_be(:xss_label) { create(:label, project: project, title: '<script>alert("xss");</script>') }
|
||||
|
||||
before do
|
||||
stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab")
|
||||
|
@ -204,7 +201,31 @@ RSpec.describe 'Issue Sidebar' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'as a allowed user' do
|
||||
context 'due date widget', :js do
|
||||
let(:due_date_value) { find('[data-testid="due-date"] [data-testid="sidebar-date-value"]') }
|
||||
|
||||
context 'when no due date exists' do
|
||||
before do
|
||||
visit_issue(project, issue)
|
||||
end
|
||||
|
||||
it "displays 'None'" do
|
||||
expect(due_date_value.text).to have_content 'None'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when due date exists' do
|
||||
before do
|
||||
visit_issue(project, issue_with_due_date)
|
||||
end
|
||||
|
||||
it "displays the due date" do
|
||||
expect(due_date_value.text).to have_content mock_date.strftime('%b %-d, %Y')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'as an allowed user' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
visit_issue(project, issue)
|
||||
|
@ -238,6 +259,12 @@ RSpec.describe 'Issue Sidebar' do
|
|||
end
|
||||
|
||||
context 'editing issue milestone', :js do
|
||||
let_it_be(:milestone_expired) { create(:milestone, project: project, due_date: 5.days.ago) }
|
||||
let_it_be(:milestone_no_duedate) { create(:milestone, project: project, title: 'Foo - No due date') }
|
||||
let_it_be(:milestone1) { create(:milestone, project: project, title: 'Milestone-1', due_date: 20.days.from_now) }
|
||||
let_it_be(:milestone2) { create(:milestone, project: project, title: 'Milestone-2', due_date: 15.days.from_now) }
|
||||
let_it_be(:milestone3) { create(:milestone, project: project, title: 'Milestone-3', due_date: 10.days.from_now) }
|
||||
|
||||
before do
|
||||
page.within('.block.milestone > .title') do
|
||||
click_on 'Edit'
|
||||
|
@ -426,6 +453,8 @@ RSpec.describe 'Issue Sidebar' do
|
|||
|
||||
def visit_issue(project, issue)
|
||||
visit project_issue_path(project, issue)
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
def open_issue_sidebar
|
||||
|
|
|
@ -406,6 +406,12 @@ RSpec.describe "Issues > User edits issue", :js do
|
|||
end
|
||||
|
||||
context 'update due date' do
|
||||
before do
|
||||
# Due date widget uses GraphQL and needs to wait for requests to come back
|
||||
# The date picker won't be rendered before requests complete
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it 'adds due date to issue' do
|
||||
date = Date.today.at_beginning_of_month + 2.days
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ RSpec.describe 'Project navbar' do
|
|||
|
||||
it 'redirects to value stream when Analytics item is clicked' do
|
||||
page.within('.sidebar-top-level-items') do
|
||||
find('[data-qa-selector=analytics_anchor]').click
|
||||
find('.shortcuts-analytics').click
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"due_date": { "type": ["string", "null"] },
|
||||
"relative_position": { "type": ["integer", "null"] },
|
||||
"time_estimate": { "type": "integer" },
|
||||
"type": { "type": "string", "enum": ["ISSUE", "INCIDENT", "TEST_CASE", "REQUIREMENT"] },
|
||||
"issue_sidebar_endpoint": { "type": "string" },
|
||||
"toggle_subscription_endpoint": { "type": "string" },
|
||||
"assignable_labels_endpoint": { "type": "string" },
|
||||
|
|
|
@ -80,6 +80,12 @@ describe('Sidebar date Widget', () => {
|
|||
expect(findPopoverIcon().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not render GlDatePicker', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findDatePicker().exists()).toBe(false);
|
||||
});
|
||||
|
||||
describe('when issuable has no due date', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent({
|
||||
|
@ -114,8 +120,15 @@ describe('Sidebar date Widget', () => {
|
|||
});
|
||||
|
||||
it('uses a correct prop to set the initial date for GlDatePicker', () => {
|
||||
expect(findDatePicker().props('value')).toBe(null);
|
||||
expect(findDatePicker().props('defaultDate')).toEqual(wrapper.vm.parsedDate);
|
||||
expect(findDatePicker().props()).toMatchObject({
|
||||
value: null,
|
||||
autocomplete: 'off',
|
||||
defaultDate: expect.any(Object),
|
||||
});
|
||||
});
|
||||
|
||||
it('renders GlDatePicker', async () => {
|
||||
expect(findDatePicker().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -21,17 +21,37 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Skip do
|
|||
before do
|
||||
allow(pipeline).to receive(:git_commit_message)
|
||||
.and_return('commit message [ci skip]')
|
||||
|
||||
step.perform!
|
||||
end
|
||||
|
||||
it 'breaks the chain' do
|
||||
step.perform!
|
||||
|
||||
expect(step.break?).to be true
|
||||
end
|
||||
|
||||
it 'skips the pipeline' do
|
||||
step.perform!
|
||||
|
||||
expect(pipeline.reload).to be_skipped
|
||||
end
|
||||
|
||||
it 'calls ensure_project_iid explicitly' do
|
||||
expect(pipeline).to receive(:ensure_project_iid!)
|
||||
|
||||
step.perform!
|
||||
end
|
||||
|
||||
context 'when the ci_pipeline_ensure_iid_on_save feature flag is off' do
|
||||
before do
|
||||
stub_feature_flags(ci_pipeline_ensure_iid_on_skip: false)
|
||||
end
|
||||
|
||||
it 'does not call ensure_project_iid explicitly' do
|
||||
expect(pipeline).not_to receive(:ensure_project_iid!)
|
||||
|
||||
step.perform!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline has not been skipped' do
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::Menus::AnalyticsMenu do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
||||
let(:user) { project.owner }
|
||||
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project, current_ref: project.repository.root_ref) }
|
||||
|
||||
subject { described_class.new(context) }
|
||||
|
||||
describe '#render?' do
|
||||
context 'whe user cannot read analytics' do
|
||||
let(:user) { nil }
|
||||
|
||||
it 'returns false' do
|
||||
expect(subject.render?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'whe user can read analytics' do
|
||||
it 'returns true' do
|
||||
expect(subject.render?).to be true
|
||||
end
|
||||
|
||||
context 'when menu does not have any menu items' do
|
||||
it 'returns false' do
|
||||
allow(subject).to receive(:has_items?).and_return(false)
|
||||
|
||||
expect(subject.render?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when menu has menu items' do
|
||||
it 'returns true' do
|
||||
expect(subject.render?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#link' do
|
||||
it 'returns link to the value stream page' do
|
||||
expect(subject.link).to include('/-/value_stream_analytics')
|
||||
end
|
||||
|
||||
context 'when Value Stream is not visible' do
|
||||
it 'returns link to the the first visible menu item' do
|
||||
allow(subject).to receive(:cycle_analytics_menu_item).and_return(nil)
|
||||
|
||||
expect(subject.link).to eq subject.items.first.link
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Menu items' do
|
||||
subject { described_class.new(context).items.index { |e| e.item_id == item_id } }
|
||||
|
||||
describe 'CI/CD' do
|
||||
let(:item_id) { :ci_cd_analytics }
|
||||
|
||||
specify { is_expected.not_to be_nil }
|
||||
|
||||
describe 'when the project repository is empty' do
|
||||
before do
|
||||
allow(project).to receive(:empty_repo?).and_return(true)
|
||||
end
|
||||
|
||||
specify { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
describe 'when builds access level is DISABLED' do
|
||||
before do
|
||||
project.project_feature.update!(builds_access_level: Featurable::DISABLED)
|
||||
end
|
||||
|
||||
specify { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
describe 'when the user does not have access' do
|
||||
let(:user) { nil }
|
||||
|
||||
specify { is_expected.to be_nil }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Repository' do
|
||||
let(:item_id) { :repository_analytics }
|
||||
|
||||
specify { is_expected.not_to be_nil }
|
||||
|
||||
describe 'when the project repository is empty' do
|
||||
before do
|
||||
allow(project).to receive(:empty_repo?).and_return(true)
|
||||
end
|
||||
|
||||
specify { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
describe 'when the user does not have access' do
|
||||
let(:user) { nil }
|
||||
|
||||
specify { is_expected.to be_nil }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Value Stream' do
|
||||
let(:item_id) { :cycle_analytics }
|
||||
|
||||
specify { is_expected.not_to be_nil }
|
||||
|
||||
describe 'when the user does not have access' do
|
||||
let(:user) { nil }
|
||||
|
||||
specify { is_expected.to be_nil }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -21,6 +21,23 @@ RSpec.describe Ci::CreateWebIdeTerminalService do
|
|||
expect(subject[:pipeline].stages.count).to eq(1)
|
||||
expect(subject[:pipeline].builds.count).to eq(1)
|
||||
end
|
||||
|
||||
it 'calls ensure_project_iid explicitly' do
|
||||
expect_next_instance_of(Ci::Pipeline) do |instance|
|
||||
expect(instance).to receive(:ensure_project_iid!).twice
|
||||
end
|
||||
subject
|
||||
end
|
||||
|
||||
context 'when the ci_pipeline_ensure_iid_on_save feature flag is off' do
|
||||
it 'does not call ensure_project_iid explicitly' do
|
||||
stub_feature_flags(ci_pipeline_ensure_iid_on_save: false)
|
||||
expect_next_instance_of(Ci::Pipeline) do |instance|
|
||||
expect(instance).to receive(:ensure_project_iid!).once
|
||||
end
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
|
|
|
@ -220,7 +220,7 @@ RSpec.describe Tooling::Danger::ProjectHelper do
|
|||
|
||||
describe '.local_warning_message' do
|
||||
it 'returns an informational message with rules that can run' do
|
||||
expect(described_class.local_warning_message).to eq('==> Only the following Danger rules can be run locally: changelog, changes_size, commit_messages, database, datateam, documentation, duplicate_yarn_dependencies, eslint, karma, pajamas, pipeline, prettier, product_intelligence, utility_css')
|
||||
expect(described_class.local_warning_message).to eq('==> Only the following Danger rules can be run locally: changelog, commit_messages, database, datateam, documentation, duplicate_yarn_dependencies, eslint, karma, pajamas, pipeline, prettier, product_intelligence, utility_css')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -650,6 +650,68 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'Analytics' do
|
||||
it 'top level navigation link is visible points to the value stream page' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_link('Analytics', href: project_cycle_analytics_path(project))
|
||||
end
|
||||
|
||||
describe 'CI/CD' do
|
||||
it 'has a link to the CI/CD analytics page' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_link('CI/CD', href: charts_project_pipelines_path(project))
|
||||
end
|
||||
|
||||
context 'when user does not have access' do
|
||||
let(:user) { nil }
|
||||
|
||||
it 'does not have a link to the CI/CD analytics page' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to have_link('CI/CD', href: charts_project_pipelines_path(project))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Repository' do
|
||||
it 'has a link to the repository analytics page' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_link('Repository', href: charts_project_graph_path(project, 'master'))
|
||||
end
|
||||
|
||||
context 'when user does not have access' do
|
||||
let(:user) { nil }
|
||||
|
||||
it 'does not have a link to the repository analytics page' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to have_link('Repository', href: charts_project_graph_path(project, 'master'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Value Stream' do
|
||||
it 'has a link to the value stream page' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_link('Value Stream', href: project_cycle_analytics_path(project))
|
||||
end
|
||||
|
||||
context 'when user does not have access' do
|
||||
let(:user) { nil }
|
||||
|
||||
it 'does not have a link to the value stream page' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to have_link('Value Stream', href: project_cycle_analytics_path(project))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'wiki entry tab' do
|
||||
let(:can_read_wiki) { true }
|
||||
|
||||
|
@ -736,32 +798,6 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'value stream analytics entry' do
|
||||
let(:read_cycle_analytics) { true }
|
||||
|
||||
before do
|
||||
allow(view).to receive(:can?).with(user, :read_cycle_analytics, project).and_return(read_cycle_analytics)
|
||||
end
|
||||
|
||||
describe 'when value stream analytics is enabled' do
|
||||
it 'shows the value stream analytics entry' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_link('Value Stream', href: project_cycle_analytics_path(project))
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when value stream analytics is disabled' do
|
||||
let(:read_cycle_analytics) { false }
|
||||
|
||||
it 'does not show the value stream analytics entry' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to have_link('Value Stream', href: project_cycle_analytics_path(project))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'operations settings tab' do
|
||||
describe 'archive projects' do
|
||||
before do
|
||||
|
|
|
@ -5,7 +5,6 @@ module Tooling
|
|||
module ProjectHelper
|
||||
LOCAL_RULES ||= %w[
|
||||
changelog
|
||||
changes_size
|
||||
commit_messages
|
||||
database
|
||||
datateam
|
||||
|
@ -176,26 +175,12 @@ module Tooling
|
|||
ee? ? 'gitlab' : 'gitlab-foss'
|
||||
end
|
||||
|
||||
def missing_database_labels(current_mr_labels)
|
||||
labels = if has_database_scoped_labels?(current_mr_labels)
|
||||
['database']
|
||||
else
|
||||
['database', 'database::review pending']
|
||||
end
|
||||
|
||||
labels - current_mr_labels
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ee?
|
||||
# Support former project name for `dev` and support local Danger run
|
||||
%w[gitlab gitlab-ee].include?(ENV['CI_PROJECT_NAME']) || Dir.exist?(File.expand_path('../../../ee', __dir__))
|
||||
end
|
||||
|
||||
def has_database_scoped_labels?(current_mr_labels)
|
||||
current_mr_labels.any? { |label| label.start_with?('database::') }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -283,6 +283,9 @@ func configureRoutes(u *upstream) {
|
|||
// Gem Artifact Repository
|
||||
u.route("POST", apiProjectPattern+`packages/rubygems/`, upload.BodyUploader(api, signingProxy, preparers.packages)),
|
||||
|
||||
// Terraform Module Package Repository
|
||||
u.route("PUT", apiProjectPattern+`packages/terraform/modules/`, upload.BodyUploader(api, signingProxy, preparers.packages)),
|
||||
|
||||
// We are porting API to disk acceleration
|
||||
// we need to declare each routes until we have fixed all the routes on the rails codebase.
|
||||
// Overall status can be seen at https://gitlab.com/groups/gitlab-org/-/epics/1802#current-status
|
||||
|
|
|
@ -512,6 +512,7 @@ func TestPackageFilesUpload(t *testing.T) {
|
|||
{"PUT", "/api/v4/projects/group%2Fproject/packages/generic/mypackage/0.0.1/myfile.tar.gz"},
|
||||
{"PUT", "/api/v4/projects/group%2Fproject/packages/debian/libsample0_1.2.3~alpha2-1_amd64.deb"},
|
||||
{"POST", "/api/v4/projects/group%2Fproject/packages/rubygems/api/v1/gems/sample.gem"},
|
||||
{"PUT", "/api/v4/projects/group%2Fproject/packages/terraform/modules/mymodule/mysystem/0.0.1/file"},
|
||||
}
|
||||
|
||||
for _, r := range routes {
|
||||
|
|
Loading…
Reference in New Issue