diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-05 12:10:33 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-05 12:10:33 +0000 |
commit | 023e050d82ed11d9060ce5bdaec99c3871b98164 (patch) | |
tree | ee89e2c83c2771c635a0c1daaa88fcce25f18612 | |
parent | 1c568d834d0cbe1bbbf558ac9a45940f6dbda37a (diff) | |
download | gitlab-ce-023e050d82ed11d9060ce5bdaec99c3871b98164.tar.gz |
Add latest changes from gitlab-org/gitlab@master
91 files changed, 918 insertions, 326 deletions
diff --git a/Dangerfile b/Dangerfile index 699be613f2d..37a45674e16 100644 --- a/Dangerfile +++ b/Dangerfile @@ -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 @@ -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 diff --git a/Gemfile.lock b/Gemfile.lock index 1cee984d59b..8111ff597e7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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) diff --git a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue index 584f794752d..6a68e914b84 100644 --- a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue +++ b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue @@ -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)" /> diff --git a/app/helpers/analytics/navbar_helper.rb b/app/helpers/analytics/navbar_helper.rb index 33a5028cdf1..4c7ded1ba18 100644 --- a/app/helpers/analytics/navbar_helper.rb +++ b/app/helpers/analytics/navbar_helper.rb @@ -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 diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb index 65feea4f6e0..60e37c96f61 100644 --- a/app/helpers/appearances_helper.rb +++ b/app/helpers/appearances_helper.rb @@ -83,5 +83,4 @@ module AppearancesHelper end end -AppearancesHelper.prepend_if_ee('EE::AppearancesHelper') -AppearancesHelper.prepend_if_jh('JH::AppearancesHelper') +AppearancesHelper.prepend_mod diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6d9cb0c8175..d1f3a2e53a0 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -409,5 +409,4 @@ module ApplicationHelper end end -ApplicationHelper.prepend_if_ee('EE::ApplicationHelper') -ApplicationHelper.prepend_if_jh('JH::ApplicationHelper') +ApplicationHelper.prepend_mod diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index ca936307acc..b9891172c6c 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -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, diff --git a/app/services/ci/create_web_ide_terminal_service.rb b/app/services/ci/create_web_ide_terminal_service.rb index 3b89a599180..de5e627b0fe 100644 --- a/app/services/ci/create_web_ide_terminal_service.rb +++ b/app/services/ci/create_web_ide_terminal_service.rb @@ -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 diff --git a/app/views/layouts/nav/sidebar/_project_menus.html.haml b/app/views/layouts/nav/sidebar/_project_menus.html.haml index f802488aa80..ea04d14dcda 100644 --- a/app/views/layouts/nav/sidebar/_project_menus.html.haml +++ b/app/views/layouts/nav/sidebar/_project_menus.html.haml @@ -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 diff --git a/changelogs/unreleased/300997-enable-ci_workflow_rules_variables.yml b/changelogs/unreleased/300997-enable-ci_workflow_rules_variables.yml new file mode 100644 index 00000000000..40828358bf4 --- /dev/null +++ b/changelogs/unreleased/300997-enable-ci_workflow_rules_variables.yml @@ -0,0 +1,5 @@ +--- +title: Implement variables for pipeline workflow rules +merge_request: 59970 +author: +type: added diff --git a/changelogs/unreleased/329614-issue-due-date-changes-without-user-input-2.yml b/changelogs/unreleased/329614-issue-due-date-changes-without-user-input-2.yml new file mode 100644 index 00000000000..e666b6880ff --- /dev/null +++ b/changelogs/unreleased/329614-issue-due-date-changes-without-user-input-2.yml @@ -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 diff --git a/changelogs/unreleased/ab-ci-builds-pending-partial-covering.yml b/changelogs/unreleased/ab-ci-builds-pending-partial-covering.yml new file mode 100644 index 00000000000..d6ac3b28774 --- /dev/null +++ b/changelogs/unreleased/ab-ci-builds-pending-partial-covering.yml @@ -0,0 +1,5 @@ +--- +title: Include other cols in index for pending builds +merge_request: 60997 +author: +type: performance diff --git a/changelogs/unreleased/fix-danger-changelog-bug.yml b/changelogs/unreleased/fix-danger-changelog-bug.yml new file mode 100644 index 00000000000..a87f5fd0830 --- /dev/null +++ b/changelogs/unreleased/fix-danger-changelog-bug.yml @@ -0,0 +1,5 @@ +--- +title: Fix changelog Dangerfile to convert MR IID to a string before comparison +merge_request: 60899 +author: +type: fixed diff --git a/changelogs/unreleased/issue-327906-issue-type.yml b/changelogs/unreleased/issue-327906-issue-type.yml new file mode 100644 index 00000000000..5ec69e6c38b --- /dev/null +++ b/changelogs/unreleased/issue-327906-issue-type.yml @@ -0,0 +1,5 @@ +--- +title: Added type field into Issues API +merge_request: 59648 +author: Raimund Hook @stingrayza +type: added diff --git a/config/feature_flags/development/ci_pipeline_ensure_iid_on_save.yml b/config/feature_flags/development/ci_pipeline_ensure_iid_on_save.yml new file mode 100644 index 00000000000..95b62d92ade --- /dev/null +++ b/config/feature_flags/development/ci_pipeline_ensure_iid_on_save.yml @@ -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 diff --git a/config/feature_flags/development/ci_pipeline_ensure_iid_on_skip.yml b/config/feature_flags/development/ci_pipeline_ensure_iid_on_skip.yml new file mode 100644 index 00000000000..43fb411edbf --- /dev/null +++ b/config/feature_flags/development/ci_pipeline_ensure_iid_on_skip.yml @@ -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 diff --git a/config/feature_flags/development/ci_workflow_rules_variables.yml b/config/feature_flags/development/ci_workflow_rules_variables.yml index 8915d109c83..427a07c51f6 100644 --- a/config/feature_flags/development/ci_workflow_rules_variables.yml +++ b/config/feature_flags/development/ci_workflow_rules_variables.yml @@ -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 diff --git a/config/feature_flags/development/escalation_policies_mvc.yml b/config/feature_flags/development/escalation_policies_mvc.yml new file mode 100644 index 00000000000..21766f9485e --- /dev/null +++ b/config/feature_flags/development/escalation_policies_mvc.yml @@ -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 diff --git a/config/initializers/0_inject_enterprise_edition_module.rb b/config/initializers/0_inject_enterprise_edition_module.rb index f9c82f45040..5f938c1ef37 100644 --- a/config/initializers/0_inject_enterprise_edition_module.rb +++ b/config/initializers/0_inject_enterprise_edition_module.rb @@ -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? + def include_mod + each_extension_for(name, Object, &method(:include)) end + alias_method :include_ee_mod, :include_mod - def prepend_if_jh(constant, with_descendants: false) - return unless Gitlab.jh? + private - prepend_module(constant.constantize, with_descendants) + 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 - private - 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 diff --git a/danger/changelog/Dangerfile b/danger/changelog/Dangerfile index 4c0ce5c44b5..7167ee5aad5 100644 --- a/danger/changelog/Dangerfile +++ b/danger/changelog/Dangerfile @@ -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 diff --git a/danger/changes_size/Dangerfile b/danger/changes_size/Dangerfile deleted file mode 100644 index 52e6cb65d04..00000000000 --- a/danger/changes_size/Dangerfile +++ /dev/null @@ -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 diff --git a/danger/database/Dangerfile b/danger/database/Dangerfile index af4d6ed513d..cd56ea8dd22 100644 --- a/danger/database/Dangerfile +++ b/danger/database/Dangerfile @@ -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') diff --git a/danger/feature_flag/Dangerfile b/danger/feature_flag/Dangerfile index d14dd97380f..88ce6393b64 100644 --- a/danger/feature_flag/Dangerfile +++ b/danger/feature_flag/Dangerfile @@ -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) diff --git a/db/post_migrate/20210505092746_create_partial_covering_index_for_pending_builds.rb b/db/post_migrate/20210505092746_create_partial_covering_index_for_pending_builds.rb new file mode 100644 index 00000000000..a1e1dbbeafe --- /dev/null +++ b/db/post_migrate/20210505092746_create_partial_covering_index_for_pending_builds.rb @@ -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 diff --git a/db/schema_migrations/20210505092746 b/db/schema_migrations/20210505092746 new file mode 100644 index 00000000000..b23d8ee3538 --- /dev/null +++ b/db/schema_migrations/20210505092746 @@ -0,0 +1 @@ +ccf7bce753adabfd7dd8a68fd49853514367f11af42879cae1b6aa28e4ebe94c
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index fce0a085dac..624e74bdd9a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -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)); diff --git a/doc/api/issues.md b/doc/api/issues.md index cd720748cae..5ed3526cd7f 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -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", diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 49daa2b17fb..f01a1c572d2 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -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: diff --git a/doc/development/jh_features_review.md b/doc/development/jh_features_review.md new file mode 100644 index 00000000000..260da2d7ef2 --- /dev/null +++ b/doc/development/jh_features_review.md @@ -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. diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md index 915d049b7c9..a7a2f5b912c 100644 --- a/doc/user/project/issues/managing_issues.md +++ b/doc/user/project/issues/managing_issues.md @@ -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. diff --git a/lib/api/entities/issue_basic.rb b/lib/api/entities/issue_basic.rb index cf96c6556ec..a9ec2632ed4 100644 --- a/lib/api/entities/issue_basic.rb +++ b/lib/api/entities/issue_basic.rb @@ -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 diff --git a/lib/gitlab.rb b/lib/gitlab.rb index ddf08c8dc20..86bb2f662e5 100644 --- a/lib/gitlab.rb +++ b/lib/gitlab.rb @@ -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 diff --git a/lib/gitlab/ci/pipeline/chain/skip.rb b/lib/gitlab/ci/pipeline/chain/skip.rb index df92e229f12..bea0c0ea115 100644 --- a/lib/gitlab/ci/pipeline/chain/skip.rb +++ b/lib/gitlab/ci/pipeline/chain/skip.rb @@ -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 diff --git a/lib/gitlab/ci/pipeline/chain/validate/security_orchestration_policy.rb b/lib/gitlab/ci/pipeline/chain/validate/security_orchestration_policy.rb new file mode 100644 index 00000000000..de59a5d51e3 --- /dev/null +++ b/lib/gitlab/ci/pipeline/chain/validate/security_orchestration_policy.rb @@ -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') diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb index c4867746b0f..231f2a977c0 100644 --- a/lib/gitlab/import_export.rb +++ b/lib/gitlab/import_export.rb @@ -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 diff --git a/lib/gitlab/subscription_portal.rb b/lib/gitlab/subscription_portal.rb index 3072210d7c8..1ba1d70a13c 100644 --- a/lib/gitlab/subscription_portal.rb +++ b/lib/gitlab/subscription_portal.rb @@ -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 diff --git a/lib/sidebars/projects/menus/analytics_menu.rb b/lib/sidebars/projects/menus/analytics_menu.rb new file mode 100644 index 00000000000..b8a4e0171a7 --- /dev/null +++ b/lib/sidebars/projects/menus/analytics_menu.rb @@ -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') diff --git a/lib/sidebars/projects/panel.rb b/lib/sidebars/projects/panel.rb index 58f2e9e7fb4..8d81c197f71 100644 --- a/lib/sidebars/projects/panel.rb +++ b/lib/sidebars/projects/panel.rb @@ -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 diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 7d02696a541..16e13d780e0 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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 "" diff --git a/qa/qa/page/admin/menu.rb b/qa/qa/page/admin/menu.rb index 37275465221..4c8ccc62c4f 100644 --- a/qa/qa/page/admin/menu.rb +++ b/qa/qa/page/admin/menu.rb @@ -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) diff --git a/qa/qa/page/admin/overview/groups/edit.rb b/qa/qa/page/admin/overview/groups/edit.rb index c96e953d05b..f63891be1c5 100644 --- a/qa/qa/page/admin/overview/groups/edit.rb +++ b/qa/qa/page/admin/overview/groups/edit.rb @@ -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) diff --git a/qa/qa/page/component/issue_board/show.rb b/qa/qa/page/component/issue_board/show.rb index dbf4dc30116..8a87b130c0c 100644 --- a/qa/qa/page/component/issue_board/show.rb +++ b/qa/qa/page/component/issue_board/show.rb @@ -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) diff --git a/qa/qa/page/dashboard/projects.rb b/qa/qa/page/dashboard/projects.rb index b9e2383a3eb..5416f09009f 100644 --- a/qa/qa/page/dashboard/projects.rb +++ b/qa/qa/page/dashboard/projects.rb @@ -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) diff --git a/qa/qa/page/file/show.rb b/qa/qa/page/file/show.rb index 28b6b3be154..f27119b6b5d 100644 --- a/qa/qa/page/file/show.rb +++ b/qa/qa/page/file/show.rb @@ -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) diff --git a/qa/qa/page/group/menu.rb b/qa/qa/page/group/menu.rb index 10c0ee1f0a9..97f4482d0c1 100644 --- a/qa/qa/page/group/menu.rb +++ b/qa/qa/page/group/menu.rb @@ -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) diff --git a/qa/qa/page/group/settings/general.rb b/qa/qa/page/group/settings/general.rb index 81ab6a0aa84..ec43d33c975 100644 --- a/qa/qa/page/group/settings/general.rb +++ b/qa/qa/page/group/settings/general.rb @@ -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) diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb index f0df901a8f0..6c4c8b274e3 100644 --- a/qa/qa/page/main/menu.rb +++ b/qa/qa/page/main/menu.rb @@ -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) diff --git a/qa/qa/page/merge_request/new.rb b/qa/qa/page/merge_request/new.rb index 46b7bbeed84..023c001cd02 100644 --- a/qa/qa/page/merge_request/new.rb +++ b/qa/qa/page/merge_request/new.rb @@ -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) diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb index e1790deb3ec..aec7ac6943f 100644 --- a/qa/qa/page/merge_request/show.rb +++ b/qa/qa/page/merge_request/show.rb @@ -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) diff --git a/qa/qa/page/milestone/show.rb b/qa/qa/page/milestone/show.rb index 42efbd4ea30..f5975309597 100644 --- a/qa/qa/page/milestone/show.rb +++ b/qa/qa/page/milestone/show.rb @@ -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) diff --git a/qa/qa/page/profile/menu.rb b/qa/qa/page/profile/menu.rb index 41c350f94ef..fe039ea44e0 100644 --- a/qa/qa/page/profile/menu.rb +++ b/qa/qa/page/profile/menu.rb @@ -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) diff --git a/qa/qa/page/project/issue/index.rb b/qa/qa/page/project/issue/index.rb index 10ddd52719a..de0b2364d5f 100644 --- a/qa/qa/page/project/issue/index.rb +++ b/qa/qa/page/project/issue/index.rb @@ -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) diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb index db2f5f9b3dc..0e88a410fdd 100644 --- a/qa/qa/page/project/issue/show.rb +++ b/qa/qa/page/project/issue/show.rb @@ -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) diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb index 8c70d0874c4..7214dded015 100644 --- a/qa/qa/page/project/job/show.rb +++ b/qa/qa/page/project/job/show.rb @@ -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) diff --git a/qa/qa/page/project/menu.rb b/qa/qa/page/project/menu.rb index a7c6637bb89..71fe4c55d2c 100644 --- a/qa/qa/page/project/menu.rb +++ b/qa/qa/page/project/menu.rb @@ -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) diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb index ebef1a1a972..9da6bb75eb8 100644 --- a/qa/qa/page/project/new.rb +++ b/qa/qa/page/project/new.rb @@ -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) diff --git a/qa/qa/page/project/operations/metrics/show.rb b/qa/qa/page/project/operations/metrics/show.rb index 6e8a52ab2e6..9e485bb2e15 100644 --- a/qa/qa/page/project/operations/metrics/show.rb +++ b/qa/qa/page/project/operations/metrics/show.rb @@ -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) diff --git a/qa/qa/page/project/packages/index.rb b/qa/qa/page/project/packages/index.rb index 396d3373b8a..6c6448bb196 100644 --- a/qa/qa/page/project/packages/index.rb +++ b/qa/qa/page/project/packages/index.rb @@ -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) diff --git a/qa/qa/page/project/pipeline/index.rb b/qa/qa/page/project/pipeline/index.rb index 3cb466abce9..abb21bb38ce 100644 --- a/qa/qa/page/project/pipeline/index.rb +++ b/qa/qa/page/project/pipeline/index.rb @@ -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) diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb index c5887b84be6..67e17131d7b 100644 --- a/qa/qa/page/project/pipeline/show.rb +++ b/qa/qa/page/project/pipeline/show.rb @@ -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) diff --git a/qa/qa/page/project/settings/ci_cd.rb b/qa/qa/page/project/settings/ci_cd.rb index 7224fdae10e..d698fa20cf1 100644 --- a/qa/qa/page/project/settings/ci_cd.rb +++ b/qa/qa/page/project/settings/ci_cd.rb @@ -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) diff --git a/qa/qa/page/project/settings/integrations.rb b/qa/qa/page/project/settings/integrations.rb index 6f5c50eac52..3ace478ab58 100644 --- a/qa/qa/page/project/settings/integrations.rb +++ b/qa/qa/page/project/settings/integrations.rb @@ -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) diff --git a/qa/qa/page/project/settings/main.rb b/qa/qa/page/project/settings/main.rb index 48af635bb79..c544bda5662 100644 --- a/qa/qa/page/project/settings/main.rb +++ b/qa/qa/page/project/settings/main.rb @@ -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) diff --git a/qa/qa/page/project/settings/merge_request.rb b/qa/qa/page/project/settings/merge_request.rb index 96ef9ade292..781f3d4d5af 100644 --- a/qa/qa/page/project/settings/merge_request.rb +++ b/qa/qa/page/project/settings/merge_request.rb @@ -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) diff --git a/qa/qa/page/project/settings/mirroring_repositories.rb b/qa/qa/page/project/settings/mirroring_repositories.rb index ce369c90a9f..1e47d4785f9 100644 --- a/qa/qa/page/project/settings/mirroring_repositories.rb +++ b/qa/qa/page/project/settings/mirroring_repositories.rb @@ -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) diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb index 6616921f34c..e54012c0406 100644 --- a/qa/qa/page/project/settings/protected_branches.rb +++ b/qa/qa/page/project/settings/protected_branches.rb @@ -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) diff --git a/qa/qa/page/project/settings/protected_tags.rb b/qa/qa/page/project/settings/protected_tags.rb index bf8f349cfd5..090b677402f 100644 --- a/qa/qa/page/project/settings/protected_tags.rb +++ b/qa/qa/page/project/settings/protected_tags.rb @@ -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) diff --git a/qa/qa/page/project/settings/repository.rb b/qa/qa/page/project/settings/repository.rb index 407c131fa73..b8a0b365195 100644 --- a/qa/qa/page/project/settings/repository.rb +++ b/qa/qa/page/project/settings/repository.rb @@ -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) diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index d8c6b3881bd..6cc99b6cfc1 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -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) diff --git a/qa/qa/page/project/snippet/index.rb b/qa/qa/page/project/snippet/index.rb index a221abc4196..0c88c2cc6f9 100644 --- a/qa/qa/page/project/snippet/index.rb +++ b/qa/qa/page/project/snippet/index.rb @@ -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) diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb index 3f04538a311..e8e83a10a7f 100644 --- a/qa/qa/page/project/web_ide/edit.rb +++ b/qa/qa/page/project/web_ide/edit.rb @@ -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) diff --git a/qa/qa/page/project/wiki/show.rb b/qa/qa/page/project/wiki/show.rb index f3573e3cdd3..7120fdece76 100644 --- a/qa/qa/page/project/wiki/show.rb +++ b/qa/qa/page/project/wiki/show.rb @@ -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) diff --git a/qa/qa/page/registration/welcome.rb b/qa/qa/page/registration/welcome.rb index 394e94b6414..72b5094fd0b 100644 --- a/qa/qa/page/registration/welcome.rb +++ b/qa/qa/page/registration/welcome.rb @@ -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) diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index e4b92dc2e0d..f6ccbce5d37 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -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) diff --git a/qa/qa/scenario/test/sanity/selectors.rb b/qa/qa/scenario/test/sanity/selectors.rb index b2c90ab2e2a..0da08ae03e2 100644 --- a/qa/qa/scenario/test/sanity/selectors.rb +++ b/qa/qa/scenario/test/sanity/selectors.rb @@ -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) diff --git a/scripts/sync-reports b/scripts/sync-reports deleted file mode 100755 index 73afd276e6c..00000000000 --- a/scripts/sync-reports +++ /dev/null @@ -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 diff --git a/spec/config/inject_enterprise_edition_module_spec.rb b/spec/config/inject_enterprise_edition_module_spec.rb new file mode 100644 index 00000000000..c65d909cc6b --- /dev/null +++ b/spec/config/inject_enterprise_edition_module_spec.rb @@ -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 diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb index da9def60ff9..d147476f1ab 100644 --- a/spec/features/issues/issue_sidebar_spec.rb +++ b/spec/features/issues/issue_sidebar_spec.rb @@ -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 diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb index be2955527be..cb4a5a32762 100644 --- a/spec/features/issues/user_edits_issue_spec.rb +++ b/spec/features/issues/user_edits_issue_spec.rb @@ -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 diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb index 9bb8f0b2f21..5ab75a6b914 100644 --- a/spec/features/projects/navbar_spec.rb +++ b/spec/features/projects/navbar_spec.rb @@ -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 diff --git a/spec/fixtures/api/schemas/issue.json b/spec/fixtures/api/schemas/issue.json index bb6e5c0de10..aefba89d9e2 100644 --- a/spec/fixtures/api/schemas/issue.json +++ b/spec/fixtures/api/schemas/issue.json @@ -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" }, diff --git a/spec/frontend/sidebar/components/date/sidebar_date_widget_spec.js b/spec/frontend/sidebar/components/date/sidebar_date_widget_spec.js index 273235fe197..91cbcc6cc27 100644 --- a/spec/frontend/sidebar/components/date/sidebar_date_widget_spec.js +++ b/spec/frontend/sidebar/components/date/sidebar_date_widget_spec.js @@ -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); }); }); diff --git a/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb index e4768f2ef0d..ae427eaf403 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb @@ -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 diff --git a/spec/lib/sidebars/projects/menus/analytics_menu_spec.rb b/spec/lib/sidebars/projects/menus/analytics_menu_spec.rb new file mode 100644 index 00000000000..c109631fabe --- /dev/null +++ b/spec/lib/sidebars/projects/menus/analytics_menu_spec.rb @@ -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 diff --git a/spec/services/ci/create_web_ide_terminal_service_spec.rb b/spec/services/ci/create_web_ide_terminal_service_spec.rb index e8a549650a6..a0974247918 100644 --- a/spec/services/ci/create_web_ide_terminal_service_spec.rb +++ b/spec/services/ci/create_web_ide_terminal_service_spec.rb @@ -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 diff --git a/spec/tooling/danger/project_helper_spec.rb b/spec/tooling/danger/project_helper_spec.rb index 5d106f08402..6bec176b39b 100644 --- a/spec/tooling/danger/project_helper_spec.rb +++ b/spec/tooling/danger/project_helper_spec.rb @@ -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 diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb index b86164a6639..d5320b2d044 100644 --- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb +++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb @@ -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 diff --git a/tooling/danger/project_helper.rb b/tooling/danger/project_helper.rb index 7aac0de0b6b..b60a3aa1adc 100644 --- a/tooling/danger/project_helper.rb +++ b/tooling/danger/project_helper.rb @@ -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 diff --git a/workhorse/internal/upstream/routes.go b/workhorse/internal/upstream/routes.go index d95646b91f7..a2a5f93613b 100644 --- a/workhorse/internal/upstream/routes.go +++ b/workhorse/internal/upstream/routes.go @@ -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 diff --git a/workhorse/upload_test.go b/workhorse/upload_test.go index 90712c0af72..a44bf1a4aeb 100644 --- a/workhorse/upload_test.go +++ b/workhorse/upload_test.go @@ -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 { |