diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-17 12:10:08 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-17 12:10:08 +0300 |
commit | 325318e2ddfcaedf0527053dd3c9bd62db547089 (patch) | |
tree | 2525b4135802427a95233219d9d339ceadb51280 | |
parent | c64b892786865a3b87701450c6ca62fcab0fa044 (diff) |
Add latest changes from gitlab-org/gitlab@master
51 files changed, 523 insertions, 297 deletions
diff --git a/app/assets/javascripts/alert_management/components/alert_details.vue b/app/assets/javascripts/alert_management/components/alert_details.vue index 8c3ec527ef6..49eff61e12f 100644 --- a/app/assets/javascripts/alert_management/components/alert_details.vue +++ b/app/assets/javascripts/alert_management/components/alert_details.vue @@ -324,6 +324,12 @@ export default { </div> <div class="gl-pl-2" data-testid="service">{{ alert.service }}</div> </div> + <div v-if="alert.runbook" class="gl-my-5 gl-display-flex"> + <div class="bold gl-w-13 gl-text-right gl-pr-3"> + {{ s__('AlertManagement|Runbook') }}: + </div> + <div class="gl-pl-2" data-testid="runbook">{{ alert.runbook }}</div> + </div> <template> <div v-if="alert.notes.nodes" class="issuable-discussion py-5"> <ul class="notes main-notes-list timeline"> diff --git a/app/assets/javascripts/alert_management/graphql/fragments/detail_item.fragment.graphql b/app/assets/javascripts/alert_management/graphql/fragments/detail_item.fragment.graphql index 92eb828bdf8..0712ff12c23 100644 --- a/app/assets/javascripts/alert_management/graphql/fragments/detail_item.fragment.graphql +++ b/app/assets/javascripts/alert_management/graphql/fragments/detail_item.fragment.graphql @@ -11,6 +11,7 @@ fragment AlertDetailItem on AlertManagementAlert { updatedAt endedAt details + runbook todos { nodes { id diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js index 6e425b82a82..127d24c5473 100644 --- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js +++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js @@ -93,10 +93,6 @@ const createPipelineHeaderApp = mediator => { }; const createTestDetails = () => { - if (!window.gon?.features?.junitPipelineView) { - return; - } - const el = document.querySelector('#js-pipeline-tests-detail'); const { summaryEndpoint, suiteEndpoint } = el?.dataset || {}; diff --git a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue index b8a8cb940e7..31ac4510add 100644 --- a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue +++ b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue @@ -56,7 +56,7 @@ export default { return `${this.pipelinePath}/test_report`; }, showViewFullReport() { - return Boolean(this.glFeatures.junitPipelineView) && this.pipelinePath.length; + return this.pipelinePath.length; }, }, created() { @@ -116,6 +116,7 @@ export default { <template v-if="showViewFullReport" #actionButtons> <gl-button :href="testTabURL" + target="_blank" icon="external-link" data-testid="group-test-reports-full-link" class="gl-mr-3" diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 9b246979860..b217b366ee5 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -43,7 +43,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo before_action do push_frontend_feature_flag(:vue_issuable_sidebar, @project.group) - push_frontend_feature_flag(:junit_pipeline_view, @project.group) end around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions] diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index 55dc03479b5..bfe23eb1035 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -12,7 +12,6 @@ class Projects::PipelinesController < Projects::ApplicationController before_action :authorize_create_pipeline!, only: [:new, :create] before_action :authorize_update_pipeline!, only: [:retry, :cancel] before_action do - push_frontend_feature_flag(:junit_pipeline_view, project) push_frontend_feature_flag(:filter_pipelines_search, project, default_enabled: true) push_frontend_feature_flag(:dag_pipeline_tab, project, default_enabled: true) push_frontend_feature_flag(:pipelines_security_report_summary, project) @@ -177,8 +176,6 @@ class Projects::PipelinesController < Projects::ApplicationController end def test_report - return unless Feature.enabled?(:junit_pipeline_view, project) - respond_to do |format| format.html do render 'show' diff --git a/app/models/concerns/has_wiki.rb b/app/models/concerns/has_wiki.rb index 4dd72216e77..3e7cb940a62 100644 --- a/app/models/concerns/has_wiki.rb +++ b/app/models/concerns/has_wiki.rb @@ -17,7 +17,7 @@ module HasWiki def wiki strong_memoize(:wiki) do - Wiki.for_container(self, self.owner) + Wiki.for_container(self, self.default_owner) end end diff --git a/app/models/group.rb b/app/models/group.rb index 440b2c6362b..f8cbaa2495c 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -563,6 +563,10 @@ class Group < Namespace all_projects.update_all(shared_runners_enabled: false) end + def default_owner + owners.first || parent&.default_owner || owner + end + private def update_two_factor_requirement diff --git a/app/models/project.rb b/app/models/project.rb index 5e1822f1a34..e1b6a9c41dd 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1395,6 +1395,16 @@ class Project < ApplicationRecord group || namespace.try(:owner) end + def default_owner + obj = owner + + if obj.respond_to?(:default_owner) + obj.default_owner + else + obj + end + end + def to_ability_name model_name.singular end diff --git a/app/models/wiki.rb b/app/models/wiki.rb index 4c497cc304c..30273d646cf 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -35,6 +35,7 @@ class Wiki def initialize(container, user = nil) @container = container @user = user + raise ArgumentError, "user must be a User, got #{user.class}" if user && !user.is_a?(User) end def path diff --git a/app/services/alert_management/alerts/update_service.rb b/app/services/alert_management/alerts/update_service.rb index 0b7216cd9f8..18d615aa7e7 100644 --- a/app/services/alert_management/alerts/update_service.rb +++ b/app/services/alert_management/alerts/update_service.rb @@ -96,12 +96,12 @@ module AlertManagement end def handle_assignement(old_assignees) - assign_todo + assign_todo(old_assignees) add_assignee_system_note(old_assignees) end - def assign_todo - todo_service.assign_alert(alert, current_user) + def assign_todo(old_assignees) + todo_service.reassigned_assignable(alert, current_user, old_assignees) end def add_assignee_system_note(old_assignees) diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb index abbb68aaf94..3921dbefd06 100644 --- a/app/services/event_create_service.rb +++ b/app/services/event_create_service.rb @@ -109,7 +109,7 @@ class EventCreateService def wiki_event(wiki_page_meta, author, action, fingerprint) raise IllegalActionError, action unless Event::WIKI_ACTIONS.include?(action) - Gitlab::UsageDataCounters::TrackUniqueActions.track_action(event_action: action, event_target: wiki_page_meta.class, author_id: author.id) + Gitlab::UsageDataCounters::TrackUniqueActions.track_event(event_action: action, event_target: wiki_page_meta.class, author_id: author.id) duplicate = Event.for_wiki_meta(wiki_page_meta).for_fingerprint(fingerprint).first return duplicate if duplicate.present? @@ -154,7 +154,7 @@ class EventCreateService result = Event.insert_all(attribute_sets, returning: %w[id]) tuples.each do |record, status, _| - Gitlab::UsageDataCounters::TrackUniqueActions.track_action(event_action: status, event_target: record.class, author_id: current_user.id) + Gitlab::UsageDataCounters::TrackUniqueActions.track_event(event_action: status, event_target: record.class, author_id: current_user.id) end result @@ -172,7 +172,7 @@ class EventCreateService new_event end - Gitlab::UsageDataCounters::TrackUniqueActions.track_action(event_action: :pushed, event_target: Project, author_id: current_user.id) + Gitlab::UsageDataCounters::TrackUniqueActions.track_event(event_action: :pushed, event_target: Project, author_id: current_user.id) Users::LastPushEventService.new(current_user) .cache_last_push_event(event) diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb index 8835af3659d..ac7baba3b7c 100644 --- a/app/services/issues/update_service.rb +++ b/app/services/issues/update_service.rb @@ -43,7 +43,7 @@ module Issues if issue.assignees != old_assignees create_assignee_note(issue, old_assignees) notification_service.async.reassigned_issue(issue, current_user, old_assignees) - todo_service.reassigned_issuable(issue, current_user, old_assignees) + todo_service.reassigned_assignable(issue, current_user, old_assignees) end if issue.previous_changes.include?('confidential') diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb index 29e0c22b155..cf02158b629 100644 --- a/app/services/merge_requests/update_service.rb +++ b/app/services/merge_requests/update_service.rb @@ -105,7 +105,7 @@ module MergeRequests def handle_assignees_change(merge_request, old_assignees) create_assignee_note(merge_request, old_assignees) notification_service.async.reassigned_merge_request(merge_request, current_user, old_assignees) - todo_service.reassigned_issuable(merge_request, current_user, old_assignees) + todo_service.reassigned_assignable(merge_request, current_user, old_assignees) end def create_branch_change_note(issuable, branch_type, old_branch, new_branch) diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb index 3aa0e5650ee..c253154c1b7 100644 --- a/app/services/resource_access_tokens/create_service.rb +++ b/app/services/resource_access_tokens/create_service.rb @@ -32,6 +32,8 @@ module ResourceAccessTokens attr_reader :resource_type, :resource def feature_enabled? + return false if ::Gitlab.com? + ::Feature.enabled?(:resource_access_token, resource, default_enabled: true) end diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb index ec15bdde8d7..a3db2ae7947 100644 --- a/app/services/todo_service.rb +++ b/app/services/todo_service.rb @@ -49,11 +49,11 @@ class TodoService todo_users.each(&:update_todos_count_cache) end - # When we reassign an issuable we should: + # When we reassign an assignable object (issuable, alert) we should: # - # * create a pending todo for new assignee if issuable is assigned + # * create a pending todo for new assignee if object is assigned # - def reassigned_issuable(issuable, current_user, old_assignees = []) + def reassigned_assignable(issuable, current_user, old_assignees = []) create_assignment_todo(issuable, current_user, old_assignees) end @@ -154,14 +154,6 @@ class TodoService resolve_todos_for_target(awardable, current_user) end - # When assigning an alert we should: - # - # * create a pending todo for new assignee if alert is assigned - # - def assign_alert(alert, current_user) - create_assignment_todo(alert, current_user, []) - end - # When user marks a target as todo def mark_todo(target, current_user) attributes = attributes_for_todo(target.project, target, current_user, Todo::MARKED) diff --git a/app/views/projects/pipelines/_with_tabs.html.haml b/app/views/projects/pipelines/_with_tabs.html.haml index 5530033ca1b..9199fdb99d6 100644 --- a/app/views/projects/pipelines/_with_tabs.html.haml +++ b/app/views/projects/pipelines/_with_tabs.html.haml @@ -1,5 +1,4 @@ - return if pipeline_has_errors -- test_reports_enabled = Feature.enabled?(:junit_pipeline_view, @project) - dag_pipeline_tab_enabled = Feature.enabled?(:dag_pipeline_tab, @project, default_enabled: true) .tabs-holder @@ -20,11 +19,10 @@ = link_to failures_project_pipeline_path(@project, @pipeline), data: { target: '#js-tab-failures', action: 'failures', toggle: 'tab' }, class: 'failures-tab' do = _('Failed Jobs') %span.badge.badge-pill.js-failures-counter= @pipeline.failed_builds.count - - if test_reports_enabled - %li.js-tests-tab-link - = link_to test_report_project_pipeline_path(@project, @pipeline), data: { target: '#js-tab-tests', action: 'test_report', toggle: 'tab' }, class: 'test-tab' do - = s_('TestReports|Tests') - %span.badge.badge-pill.js-test-report-badge-counter= @pipeline.test_report_summary.total[:count] + %li.js-tests-tab-link + = link_to test_report_project_pipeline_path(@project, @pipeline), data: { target: '#js-tab-tests', action: 'test_report', toggle: 'tab' }, class: 'test-tab' do + = s_('TestReports|Tests') + %span.badge.badge-pill.js-test-report-badge-counter= @pipeline.test_report_summary.total[:count] = render_if_exists "projects/pipelines/tabs_holder", pipeline: @pipeline, project: @project .tab-content diff --git a/app/views/projects/settings/access_tokens/index.html.haml b/app/views/projects/settings/access_tokens/index.html.haml index 4992288a8c8..100eb5991dc 100644 --- a/app/views/projects/settings/access_tokens/index.html.haml +++ b/app/views/projects/settings/access_tokens/index.html.haml @@ -10,8 +10,9 @@ = page_title %p = _('You can generate an access token scoped to this project for each application to use the GitLab API.') - %p - = _('You can also use project access tokens to authenticate against Git over HTTP.') + -# Commented out until https://gitlab.com/gitlab-org/gitlab/-/issues/219551 is fixed + -# %p + -# = _('You can also use project access tokens to authenticate against Git over HTTP.') .col-lg-8 - if @new_project_access_token diff --git a/changelogs/unreleased/216478-remove-test-report-feature-flag.yml b/changelogs/unreleased/216478-remove-test-report-feature-flag.yml new file mode 100644 index 00000000000..e8f1259593e --- /dev/null +++ b/changelogs/unreleased/216478-remove-test-report-feature-flag.yml @@ -0,0 +1,5 @@ +--- +title: JUnit test report on pipeline detail page +merge_request: 39260 +author: +type: added diff --git a/changelogs/unreleased/missing-a-blank.yml b/changelogs/unreleased/missing-a-blank.yml new file mode 100644 index 00000000000..c04f439dd11 --- /dev/null +++ b/changelogs/unreleased/missing-a-blank.yml @@ -0,0 +1,5 @@ +--- +title: Make View full report button open link in new tab +merge_request: 39501 +author: +type: changed diff --git a/changelogs/unreleased/sy-surface-runbook-in-alert.yml b/changelogs/unreleased/sy-surface-runbook-in-alert.yml new file mode 100644 index 00000000000..a98b21f7160 --- /dev/null +++ b/changelogs/unreleased/sy-surface-runbook-in-alert.yml @@ -0,0 +1,5 @@ +--- +title: Show runbook for alert in detail view +merge_request: 39477 +author: +type: added diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index e8e2f7edd07..9b08f1e5be4 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -575,6 +575,9 @@ Gitlab.ee do Settings.cron_jobs['elastic_cluster_reindexing_cron_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['elastic_cluster_reindexing_cron_worker']['cron'] ||= '*/10 * * * *' Settings.cron_jobs['elastic_cluster_reindexing_cron_worker']['job_class'] ||= 'ElasticClusterReindexingCronWorker' + Settings.cron_jobs['elastic_remove_expired_namespace_subscriptions_from_index_cron_worker'] ||= Settingslogic.new({}) + Settings.cron_jobs['elastic_remove_expired_namespace_subscriptions_from_index_cron_worker']['cron'] ||= '10 3 * * *' + Settings.cron_jobs['elastic_remove_expired_namespace_subscriptions_from_index_cron_worker']['job_class'] ||= 'ElasticRemoveExpiredNamespaceSubscriptionsFromIndexCronWorker' Settings.cron_jobs['sync_seat_link_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['sync_seat_link_worker']['cron'] ||= "#{rand(60)} 0 * * *" Settings.cron_jobs['sync_seat_link_worker']['job_class'] = 'SyncSeatLinkWorker' diff --git a/db/migrate/20200805071842_add_index_on_end_date_and_namespace_id_to_gitlab_subscriptions.rb b/db/migrate/20200805071842_add_index_on_end_date_and_namespace_id_to_gitlab_subscriptions.rb new file mode 100644 index 00000000000..17b92b6b8a8 --- /dev/null +++ b/db/migrate/20200805071842_add_index_on_end_date_and_namespace_id_to_gitlab_subscriptions.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIndexOnEndDateAndNamespaceIdToGitlabSubscriptions < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_index :gitlab_subscriptions, [:end_date, :namespace_id] + end + + def down + remove_concurrent_index :gitlab_subscriptions, [:end_date, :namespace_id] + end +end diff --git a/db/schema_migrations/20200805071842 b/db/schema_migrations/20200805071842 new file mode 100644 index 00000000000..75810bed0d1 --- /dev/null +++ b/db/schema_migrations/20200805071842 @@ -0,0 +1 @@ +432ef9d45c8242ab8db954ceeb6a68a75ef46181dd868a30d68fef0ed6058caf
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 853c686ccd5..25af1ab11d6 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -19710,6 +19710,8 @@ CREATE INDEX index_geo_upload_deleted_events_on_upload_id ON public.geo_upload_d CREATE INDEX index_gitlab_subscription_histories_on_gitlab_subscription_id ON public.gitlab_subscription_histories USING btree (gitlab_subscription_id); +CREATE INDEX index_gitlab_subscriptions_on_end_date_and_namespace_id ON public.gitlab_subscriptions USING btree (end_date, namespace_id); + CREATE INDEX index_gitlab_subscriptions_on_hosted_plan_id ON public.gitlab_subscriptions USING btree (hosted_plan_id); CREATE UNIQUE INDEX index_gitlab_subscriptions_on_namespace_id ON public.gitlab_subscriptions USING btree (namespace_id); diff --git a/doc/administration/feature_flags.md b/doc/administration/feature_flags.md index 678ab6c5d7b..7cc7692975a 100644 --- a/doc/administration/feature_flags.md +++ b/doc/administration/feature_flags.md @@ -103,10 +103,10 @@ Some feature flags can be enabled or disabled on a per project basis: Feature.enable(:<feature flag>, Project.find(<project id>)) ``` -For example, to enable the [`:junit_pipeline_view`](../ci/junit_test_reports.md#enabling-the-junit-test-reports-feature-core-only) feature flag for project `1234`: +For example, to enable the [`:product_analytics`](../operations/product_analytics.md#enable-or-disable-product-analytics) feature flag for project `1234`: ```ruby -Feature.enable(:junit_pipeline_view, Project.find(1234)) +Feature.enable(:product_analytics, Project.find(1234)) ``` `Feature.enable` and `Feature.disable` always return `nil`, this is not an indication that the command failed: diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 254c2bec304..9263dce0898 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -1135,42 +1135,47 @@ type BoardEdge { input BoardEpicIssueInput { """ - Username of a user assigned to issues + Filter by assignee username """ assigneeUsername: [String] """ - Username of the issues author + Filter by author username """ authorUsername: String """ - Epic ID applied to issues + Filter by epic ID """ epicId: String """ - Label applied to issues + Filter by label name """ labelName: [String] """ - Milestone applied to issues + Filter by milestone title """ milestoneTitle: String """ - Reaction emoji applied to issues + Filter by reaction emoji """ myReactionEmoji: String """ - Release applied to issues + List of negated params. Warning: this argument is experimental and a subject to change in future + """ + not: NegatedBoardEpicIssueInput + + """ + Filter by release tag """ releaseTag: String """ - Weight applied to issues + Filter by weight """ weight: String } @@ -9795,6 +9800,48 @@ type NamespaceIncreaseStorageTemporarilyPayload { namespace: Namespace } +input NegatedBoardEpicIssueInput { + """ + Filter by assignee username + """ + assigneeUsername: [String] + + """ + Filter by author username + """ + authorUsername: String + + """ + Filter by epic ID + """ + epicId: String + + """ + Filter by label name + """ + labelName: [String] + + """ + Filter by milestone title + """ + milestoneTitle: String + + """ + Filter by reaction emoji + """ + myReactionEmoji: String + + """ + Filter by release tag + """ + releaseTag: String + + """ + Filter by weight + """ + weight: String +} + type Note implements ResolvableInterface { """ User who wrote this note diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 262adffc4b5..1d791644909 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -3049,7 +3049,7 @@ "inputFields": [ { "name": "labelName", - "description": "Label applied to issues", + "description": "Filter by label name", "type": { "kind": "LIST", "name": null, @@ -3063,7 +3063,7 @@ }, { "name": "milestoneTitle", - "description": "Milestone applied to issues", + "description": "Filter by milestone title", "type": { "kind": "SCALAR", "name": "String", @@ -3073,7 +3073,7 @@ }, { "name": "assigneeUsername", - "description": "Username of a user assigned to issues", + "description": "Filter by assignee username", "type": { "kind": "LIST", "name": null, @@ -3087,7 +3087,7 @@ }, { "name": "authorUsername", - "description": "Username of the issues author", + "description": "Filter by author username", "type": { "kind": "SCALAR", "name": "String", @@ -3097,7 +3097,7 @@ }, { "name": "releaseTag", - "description": "Release applied to issues", + "description": "Filter by release tag", "type": { "kind": "SCALAR", "name": "String", @@ -3107,7 +3107,7 @@ }, { "name": "epicId", - "description": "Epic ID applied to issues", + "description": "Filter by epic ID", "type": { "kind": "SCALAR", "name": "String", @@ -3117,7 +3117,7 @@ }, { "name": "myReactionEmoji", - "description": "Reaction emoji applied to issues", + "description": "Filter by reaction emoji", "type": { "kind": "SCALAR", "name": "String", @@ -3127,13 +3127,23 @@ }, { "name": "weight", - "description": "Weight applied to issues", + "description": "Filter by weight", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null + }, + { + "name": "not", + "description": "List of negated params. Warning: this argument is experimental and a subject to change in future", + "type": { + "kind": "INPUT_OBJECT", + "name": "NegatedBoardEpicIssueInput", + "ofType": null + }, + "defaultValue": null } ], "interfaces": null, @@ -29246,6 +29256,105 @@ "possibleTypes": null }, { + "kind": "INPUT_OBJECT", + "name": "NegatedBoardEpicIssueInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "labelName", + "description": "Filter by label name", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "milestoneTitle", + "description": "Filter by milestone title", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "assigneeUsername", + "description": "Filter by assignee username", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "authorUsername", + "description": "Filter by author username", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "releaseTag", + "description": "Filter by release tag", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "epicId", + "description": "Filter by epic ID", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "myReactionEmoji", + "description": "Filter by reaction emoji", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "weight", + "description": "Filter by weight", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { "kind": "OBJECT", "name": "Note", "description": null, diff --git a/doc/ci/junit_test_reports.md b/doc/ci/junit_test_reports.md index 898c3526963..ca2d8dcc373 100644 --- a/doc/ci/junit_test_reports.md +++ b/doc/ci/junit_test_reports.md @@ -239,9 +239,8 @@ Test: ## Viewing JUnit test reports on GitLab -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24792) in GitLab 12.5. -> - It's deployed behind a feature flag, disabled by default. -> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enabling-the-junit-test-reports-feature-core-only). **(CORE ONLY)** +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24792) in GitLab 12.5 behind a feature flag (`junit_pipeline_view`), disabled by default. +> - The feature flag was removed and the feature was [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/216478) in GitLab 13.3. If JUnit XML files are generated and uploaded as part of a pipeline, these reports can be viewed inside the pipelines details page. The **Tests** tab on this page will @@ -254,22 +253,6 @@ details, including the cases that make up the suite. You can also retrieve the reports via the [GitLab API](../api/pipelines.md#get-a-pipelines-test-report). -### Enabling the JUnit test reports feature **(CORE ONLY)** - -This feature comes with the `:junit_pipeline_view` feature flag disabled by default. This -feature is disabled due to some performance issues with very large data sets. -When [the performance is improved](https://gitlab.com/groups/gitlab-org/-/epics/2854), the feature will be enabled by default. - -To enable this feature, ask a GitLab administrator with [Rails console access](../administration/feature_flags.md#how-to-enable-and-disable-features-behind-flags) to run the -following command: - -```ruby -Feature.enable(:junit_pipeline_view) - -# Enable the feature for a specific project, GitLab 13.0 and above only. -Feature.enable(:junit_pipeline_view, Project.find(<your-project-id-here>)) -``` - ## Viewing JUnit screenshots on GitLab > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202114) in GitLab 13.0. diff --git a/doc/user/project/settings/project_access_tokens.md b/doc/user/project/settings/project_access_tokens.md index 37360a5f105..cbc4895f014 100644 --- a/doc/user/project/settings/project_access_tokens.md +++ b/doc/user/project/settings/project_access_tokens.md @@ -5,20 +5,20 @@ info: "To determine the technical writer assigned to the Stage/Group associated type: reference, howto --- -# Project access tokens (Alpha) **(CORE ONLY)** - -CAUTION: **Warning:** -This is an [Alpha](https://about.gitlab.com/handbook/product/#alpha) feature, and it is subject to change at any time without -prior notice. +# Project access tokens **(CORE ONLY)** > - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2587) in GitLab 13.0. -> - It's deployed behind a feature flag, disabled by default. +> - It was [deployed](https://gitlab.com/groups/gitlab-org/-/epics/2587) behind a feature flag, disabled by default. +> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/218722) in GitLab 13.3. > - It's disabled on GitLab.com. -> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-project-access-tokens). +> - It can be enabled or disabled by project. +> - It's recommended for production use. +> - For GitLab self-managed instances, GitLab administrators can [disable it](#enable-or-disable-project-access-tokens). Project access tokens are scoped to a project and can be used to authenticate with the [GitLab API](../../../api/README.md#personalproject-access-tokens). -You can also use project access tokens with Git to authenticate over HTTP or SSH. +<!-- Commented out until https://gitlab.com/gitlab-org/gitlab/-/issues/219551 is fixed --> +<!-- You can also use project access tokens with Git to authenticate over HTTP or SSH. --> Project access tokens expire on the date you define, at midnight UTC. @@ -78,19 +78,30 @@ the following table. ### Enable or disable project access tokens -Project access tokens is an [Alpha](https://about.gitlab.com/handbook/product/#alpha) feature and is not recommended for production use. -It is deployed behind a feature flag that is **disabled by default**. +Project access tokens are 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 for your instance. +can disable it for your instance, globally or by project. + +To disable it globally: + +```ruby +Feature.disable(:resource_access_token) +``` -To enable it: +To disable it for a specific project: + +```ruby +Feature.disable(:resource_access_token, project) +``` + +To enable it globally: ```ruby Feature.enable(:resource_access_token) ``` -To disable it: +To enable it for a specific project: ```ruby -Feature.disable(:resource_access_token) +Feature.enable(:resource_access_token, project) ``` diff --git a/lib/api/ci/pipelines.rb b/lib/api/ci/pipelines.rb index bbbf3b683c5..a010e0dd761 100644 --- a/lib/api/ci/pipelines.rb +++ b/lib/api/ci/pipelines.rb @@ -110,15 +110,13 @@ module API end desc 'Gets the test report for a given pipeline' do - detail 'This feature was introduced in GitLab 13.0. Disabled by default behind feature flag `junit_pipeline_view`' + detail 'This feature was introduced in GitLab 13.0.' success TestReportEntity end params do requires :pipeline_id, type: Integer, desc: 'The pipeline ID' end get ':id/pipelines/:pipeline_id/test_report' do - not_found! unless Feature.enabled?(:junit_pipeline_view, user_project) - authorize! :read_build, pipeline present pipeline.test_reports, with: TestReportEntity, details: true diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index ccfb7b3870f..db2aff9b25a 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -607,7 +607,7 @@ module Gitlab counter = Gitlab::UsageDataCounters::TrackUniqueActions project_count = redis_usage_data do - counter.count_unique_events( + counter.count_unique( event_action: Gitlab::UsageDataCounters::TrackUniqueActions::PUSH_ACTION, date_from: time_period[:created_at].first, date_to: time_period[:created_at].last @@ -615,7 +615,7 @@ module Gitlab end design_count = redis_usage_data do - counter.count_unique_events( + counter.count_unique( event_action: Gitlab::UsageDataCounters::TrackUniqueActions::DESIGN_ACTION, date_from: time_period[:created_at].first, date_to: time_period[:created_at].last @@ -623,7 +623,7 @@ module Gitlab end wiki_count = redis_usage_data do - counter.count_unique_events( + counter.count_unique( event_action: Gitlab::UsageDataCounters::TrackUniqueActions::WIKI_ACTION, date_from: time_period[:created_at].first, date_to: time_period[:created_at].last diff --git a/lib/gitlab/usage_data_counters/track_unique_actions.rb b/lib/gitlab/usage_data_counters/track_unique_actions.rb index 686cce8e0ac..b7948b07251 100644 --- a/lib/gitlab/usage_data_counters/track_unique_actions.rb +++ b/lib/gitlab/usage_data_counters/track_unique_actions.rb @@ -27,7 +27,7 @@ module Gitlab }).freeze class << self - def track_action(event_action:, event_target:, author_id:, time: Time.zone.now) + def track_event(event_action:, event_target:, author_id:, time: Time.zone.now) return unless Gitlab::CurrentSettings.usage_ping_enabled return unless Feature.enabled?(FEATURE_FLAG) return unless valid_target?(event_target) @@ -40,7 +40,7 @@ module Gitlab Gitlab::Redis::HLL.add(key: target_key, value: author_id, expiry: KEY_EXPIRY_LENGTH) end - def count_unique_events(event_action:, date_from:, date_to:) + def count_unique(event_action:, date_from:, date_to:) keys = (date_from.to_date..date_to.to_date).map { |date| key(event_action, date) } Gitlab::Redis::HLL.count(keys: keys) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 23ae5515f11..e7e42175574 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2180,6 +2180,9 @@ msgstr "" msgid "AlertManagement|Resolved" msgstr "" +msgid "AlertManagement|Runbook" +msgstr "" + msgid "AlertManagement|Service" msgstr "" @@ -27831,9 +27834,6 @@ msgstr "" msgid "You can also upload existing files from your computer using the instructions below." msgstr "" -msgid "You can also use project access tokens to authenticate against Git over HTTP." -msgstr "" - msgid "You can always edit this later" msgstr "" diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 2f17cdd795a..ef560f6426b 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -859,113 +859,88 @@ RSpec.describe Projects::PipelinesController do end end - context 'when feature is enabled' do - before do - stub_feature_flags(junit_pipeline_view: project) - end - - context 'when pipeline does not have a test report' do - it 'renders an empty test report' do - get_test_report_json + context 'when pipeline does not have a test report' do + it 'renders an empty test report' do + get_test_report_json - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(0) - end + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['total_count']).to eq(0) end + end - context 'when pipeline has a test report' do - before do - create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build| - create(:ci_job_artifact, :junit, job: build) - end - end - - it 'renders the test report' do - get_test_report_json - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(4) - end + context 'when pipeline has a test report' do + before do + create(:ci_build, :test_reports, name: 'rspec', pipeline: pipeline) end - context 'when pipeline has a corrupt test report artifact' do - before do - create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build| - create(:ci_job_artifact, :junit_with_corrupted_data, job: build) - end + it 'renders the test report' do + get_test_report_json - get_test_report_json - end + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['total_count']).to eq(4) + end + end - it 'renders the test reports' do - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['test_suites'].count).to eq(1) - end + context 'when pipeline has a corrupt test report artifact' do + before do + create(:ci_build, :broken_test_reports, name: 'rspec', pipeline: pipeline) - it 'returns a suite_error on the suite with corrupted XML' do - expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty') - end + get_test_report_json end - context 'when junit_pipeline_screenshots_view is enabled' do - before do - stub_feature_flags(junit_pipeline_screenshots_view: project) - end - - context 'when test_report contains attachment and scope is with_attachment as a URL param' do - let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) } + it 'renders the test reports' do + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['test_suites'].count).to eq(1) + end - it 'returns a test reports with attachment' do - get_test_report_json(scope: 'with_attachment') + it 'returns a suite_error on the suite with corrupted XML' do + expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty') + end + end - expect(response).to have_gitlab_http_status(:ok) - expect(json_response["test_suites"]).to be_present - expect(json_response["test_suites"].first["test_cases"].first).to include("attachment_url") - end - end + context 'when junit_pipeline_screenshots_view is enabled' do + before do + stub_feature_flags(junit_pipeline_screenshots_view: project) + end - context 'when test_report does not contain attachment and scope is with_attachment as a URL param' do - let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) } + context 'when test_report contains attachment and scope is with_attachment as a URL param' do + let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) } - it 'returns a test reports with empty values' do - get_test_report_json(scope: 'with_attachment') + it 'returns a test reports with attachment' do + get_test_report_json(scope: 'with_attachment') - expect(response).to have_gitlab_http_status(:ok) - expect(json_response["test_suites"]).to be_empty - end + expect(response).to have_gitlab_http_status(:ok) + expect(json_response["test_suites"]).to be_present + expect(json_response["test_suites"].first["test_cases"].first).to include("attachment_url") end end - context 'when junit_pipeline_screenshots_view is disabled' do - before do - stub_feature_flags(junit_pipeline_screenshots_view: false) - end - - context 'when test_report contains attachment and scope is with_attachment as a URL param' do - let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) } + context 'when test_report does not contain attachment and scope is with_attachment as a URL param' do + let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) } - it 'returns a test reports without attachment_url' do - get_test_report_json(scope: 'with_attachment') + it 'returns a test reports with empty values' do + get_test_report_json(scope: 'with_attachment') - expect(response).to have_gitlab_http_status(:ok) - expect(json_response["test_suites"].first["test_cases"].first).not_to include("attachment_url") - end + expect(response).to have_gitlab_http_status(:ok) + expect(json_response["test_suites"]).to be_empty end end end - context 'when feature is disabled' do - let(:pipeline) { create(:ci_empty_pipeline, project: project) } - + context 'when junit_pipeline_screenshots_view is disabled' do before do - stub_feature_flags(junit_pipeline_view: false) + stub_feature_flags(junit_pipeline_screenshots_view: false) end - it 'renders empty response' do - get_test_report_json + context 'when test_report contains attachment and scope is with_attachment as a URL param' do + let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) } - expect(response).to have_gitlab_http_status(:no_content) - expect(response.body).to be_empty + it 'returns a test reports without attachment_url' do + get_test_report_json(scope: 'with_attachment') + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response["test_suites"].first["test_cases"].first).not_to include("attachment_url") + end end end diff --git a/spec/frontend/alert_management/components/alert_details_spec.js b/spec/frontend/alert_management/components/alert_details_spec.js index 5364d662591..f91f08cae63 100644 --- a/spec/frontend/alert_management/components/alert_details_spec.js +++ b/spec/frontend/alert_management/components/alert_details_spec.js @@ -118,6 +118,8 @@ describe('AlertDetails', () => { ${'monitoringTool'} | ${undefined} | ${false} ${'service'} | ${'Prometheus'} | ${true} ${'service'} | ${undefined} | ${false} + ${'runbook'} | ${undefined} | ${false} + ${'runbook'} | ${'run.com'} | ${true} `(`$desc`, ({ field, data, isShown }) => { beforeEach(() => { mountComponent({ data: { alert: { ...mockAlert, [field]: data } } }); diff --git a/spec/frontend/fixtures/test_report.rb b/spec/frontend/fixtures/test_report.rb index 16496aa901b..3d09078ba68 100644 --- a/spec/frontend/fixtures/test_report.rb +++ b/spec/frontend/fixtures/test_report.rb @@ -15,7 +15,6 @@ RSpec.describe Projects::PipelinesController, "(JavaScript fixtures)", type: :co before do sign_in(user) - stub_feature_flags(junit_pipeline_view: project) end it "pipelines/test_report.json" do diff --git a/spec/frontend/reports/components/grouped_test_reports_app_spec.js b/spec/frontend/reports/components/grouped_test_reports_app_spec.js index 017e0335569..c26e2fbc19a 100644 --- a/spec/frontend/reports/components/grouped_test_reports_app_spec.js +++ b/spec/frontend/reports/components/grouped_test_reports_app_spec.js @@ -20,10 +20,7 @@ describe('Grouped test reports app', () => { let wrapper; let mockStore; - const mountComponent = ({ - glFeatures = { junitPipelineView: false }, - props = { pipelinePath }, - } = {}) => { + const mountComponent = ({ props = { pipelinePath } } = {}) => { wrapper = mount(Component, { store: mockStore, localVue, @@ -35,9 +32,6 @@ describe('Grouped test reports app', () => { methods: { fetchReports: () => {}, }, - provide: { - glFeatures, - }, }); }; @@ -78,28 +72,17 @@ describe('Grouped test reports app', () => { }); describe('`View full report` button', () => { - it('should not render the full test report link', () => { - expect(findFullTestReportLink().exists()).toBe(false); - }); + it('should render the full test report link', () => { + const fullTestReportLink = findFullTestReportLink(); - describe('With junitPipelineView feature flag enabled', () => { - beforeEach(() => { - mountComponent({ glFeatures: { junitPipelineView: true } }); - }); - - it('should render the full test report link', () => { - const fullTestReportLink = findFullTestReportLink(); - - expect(fullTestReportLink.exists()).toBe(true); - expect(pipelinePath).not.toBe(''); - expect(fullTestReportLink.attributes('href')).toBe(`${pipelinePath}/test_report`); - }); + expect(fullTestReportLink.exists()).toBe(true); + expect(pipelinePath).not.toBe(''); + expect(fullTestReportLink.attributes('href')).toBe(`${pipelinePath}/test_report`); }); describe('Without a pipelinePath', () => { beforeEach(() => { mountComponent({ - glFeatures: { junitPipelineView: true }, props: { pipelinePath: '' }, }); }); diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb index 2576dd1bf07..f39b5280490 100644 --- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb +++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb @@ -6,8 +6,7 @@ RSpec.describe Banzai::Filter::GollumTagsFilter do include FilterSpecHelper let(:project) { create(:project) } - let(:user) { double } - let(:wiki) { ProjectWiki.new(project, user) } + let(:wiki) { ProjectWiki.new(project, nil) } describe 'validation' do it 'ensure that a :wiki key exists in context' do diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb index 7a4464a2604..d1f6ee49260 100644 --- a/spec/lib/banzai/filter/wiki_link_filter_spec.rb +++ b/spec/lib/banzai/filter/wiki_link_filter_spec.rb @@ -7,8 +7,7 @@ RSpec.describe Banzai::Filter::WikiLinkFilter do let(:namespace) { build_stubbed(:namespace, name: "wiki_link_ns") } let(:project) { build_stubbed(:project, :public, name: "wiki_link_project", namespace: namespace) } - let(:user) { double } - let(:wiki) { ProjectWiki.new(project, user) } + let(:wiki) { ProjectWiki.new(project, nil) } let(:repository_upload_folder) { Wikis::CreateAttachmentService::ATTACHMENT_PATH } it "doesn't rewrite absolute links" do diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb index 4af782c7d73..b102de24041 100644 --- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe Banzai::Pipeline::WikiPipeline do let_it_be(:namespace) { create(:namespace, name: "wiki_link_ns") } let_it_be(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) } - let_it_be(:wiki) { ProjectWiki.new(project, double(:user)) } + let_it_be(:wiki) { ProjectWiki.new(project, nil) } let_it_be(:page) { build(:wiki_page, wiki: wiki, title: 'nested/twice/start-page') } describe 'TableOfContents' do diff --git a/spec/lib/gitlab/usage_data_counters/track_unique_actions_spec.rb b/spec/lib/gitlab/usage_data_counters/track_unique_actions_spec.rb index 584d8407e79..6db77f19877 100644 --- a/spec/lib/gitlab/usage_data_counters/track_unique_actions_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/track_unique_actions_spec.rb @@ -7,12 +7,12 @@ RSpec.describe Gitlab::UsageDataCounters::TrackUniqueActions, :clean_gitlab_redi let(:time) { Time.zone.now } - def track_action(params) - track_unique_events.track_action(params) + def track_event(params) + track_unique_events.track_event(params) end - def count_unique_events(params) - track_unique_events.count_unique_events(params) + def count_unique(params) + track_unique_events.count_unique(params) end context 'tracking an event' do @@ -29,28 +29,28 @@ RSpec.describe Gitlab::UsageDataCounters::TrackUniqueActions, :clean_gitlab_redi design = Event::TARGET_TYPES[:design] wiki = Event::TARGET_TYPES[:wiki] - expect(track_action(event_action: :pushed, event_target: project, author_id: 1)).to be_truthy - expect(track_action(event_action: :pushed, event_target: project, author_id: 1)).to be_truthy - expect(track_action(event_action: :pushed, event_target: project, author_id: 2)).to be_truthy - expect(track_action(event_action: :pushed, event_target: project, author_id: 3)).to be_truthy - expect(track_action(event_action: :pushed, event_target: project, author_id: 4, time: time - 3.days)).to be_truthy - expect(track_action(event_action: :created, event_target: project, author_id: 5, time: time - 3.days)).to be_truthy + expect(track_event(event_action: :pushed, event_target: project, author_id: 1)).to be_truthy + expect(track_event(event_action: :pushed, event_target: project, author_id: 1)).to be_truthy + expect(track_event(event_action: :pushed, event_target: project, author_id: 2)).to be_truthy + expect(track_event(event_action: :pushed, event_target: project, author_id: 3)).to be_truthy + expect(track_event(event_action: :pushed, event_target: project, author_id: 4, time: time - 3.days)).to be_truthy + expect(track_event(event_action: :created, event_target: project, author_id: 5, time: time - 3.days)).to be_truthy - expect(track_action(event_action: :destroyed, event_target: design, author_id: 3)).to be_truthy - expect(track_action(event_action: :created, event_target: design, author_id: 4)).to be_truthy - expect(track_action(event_action: :updated, event_target: design, author_id: 5)).to be_truthy - expect(track_action(event_action: :pushed, event_target: design, author_id: 6)).to be_truthy + expect(track_event(event_action: :destroyed, event_target: design, author_id: 3)).to be_truthy + expect(track_event(event_action: :created, event_target: design, author_id: 4)).to be_truthy + expect(track_event(event_action: :updated, event_target: design, author_id: 5)).to be_truthy + expect(track_event(event_action: :pushed, event_target: design, author_id: 6)).to be_truthy - expect(track_action(event_action: :destroyed, event_target: wiki, author_id: 5)).to be_truthy - expect(track_action(event_action: :created, event_target: wiki, author_id: 3)).to be_truthy - expect(track_action(event_action: :updated, event_target: wiki, author_id: 4)).to be_truthy - expect(track_action(event_action: :pushed, event_target: wiki, author_id: 6)).to be_truthy + expect(track_event(event_action: :destroyed, event_target: wiki, author_id: 5)).to be_truthy + expect(track_event(event_action: :created, event_target: wiki, author_id: 3)).to be_truthy + expect(track_event(event_action: :updated, event_target: wiki, author_id: 4)).to be_truthy + expect(track_event(event_action: :pushed, event_target: wiki, author_id: 6)).to be_truthy - expect(count_unique_events(event_action: described_class::PUSH_ACTION, date_from: time, date_to: Date.today)).to eq(3) - expect(count_unique_events(event_action: described_class::PUSH_ACTION, date_from: time - 5.days, date_to: Date.tomorrow)).to eq(4) - expect(count_unique_events(event_action: described_class::DESIGN_ACTION, date_from: time - 5.days, date_to: Date.today)).to eq(3) - expect(count_unique_events(event_action: described_class::WIKI_ACTION, date_from: time - 5.days, date_to: Date.today)).to eq(3) - expect(count_unique_events(event_action: described_class::PUSH_ACTION, date_from: time - 5.days, date_to: time - 2.days)).to eq(1) + expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time, date_to: Date.today)).to eq(3) + expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time - 5.days, date_to: Date.tomorrow)).to eq(4) + expect(count_unique(event_action: described_class::DESIGN_ACTION, date_from: time - 5.days, date_to: Date.today)).to eq(3) + expect(count_unique(event_action: described_class::WIKI_ACTION, date_from: time - 5.days, date_to: Date.today)).to eq(3) + expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time - 5.days, date_to: time - 2.days)).to eq(1) end end end @@ -73,8 +73,8 @@ RSpec.describe Gitlab::UsageDataCounters::TrackUniqueActions, :clean_gitlab_redi end it 'returns the expected values' do - expect(track_action(event_action: action, event_target: target, author_id: 2)).to be_nil - expect(count_unique_events(event_action: described_class::PUSH_ACTION, date_from: time, date_to: Date.today)).to eq(0) + expect(track_event(event_action: action, event_target: target, author_id: 2)).to be_nil + expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time, date_to: Date.today)).to eq(0) end end end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 681784369e0..2fb30b3228a 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -924,14 +924,14 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do wiki = Event::TARGET_TYPES[:wiki] design = Event::TARGET_TYPES[:design] - counter.track_action(event_action: :pushed, event_target: project, author_id: 1) - counter.track_action(event_action: :pushed, event_target: project, author_id: 1) - counter.track_action(event_action: :pushed, event_target: project, author_id: 2) - counter.track_action(event_action: :pushed, event_target: project, author_id: 3) - counter.track_action(event_action: :pushed, event_target: project, author_id: 4, time: time - 3.days) - counter.track_action(event_action: :created, event_target: project, author_id: 5, time: time - 3.days) - counter.track_action(event_action: :created, event_target: wiki, author_id: 3) - counter.track_action(event_action: :created, event_target: design, author_id: 3) + counter.track_event(event_action: :pushed, event_target: project, author_id: 1) + counter.track_event(event_action: :pushed, event_target: project, author_id: 1) + counter.track_event(event_action: :pushed, event_target: project, author_id: 2) + counter.track_event(event_action: :pushed, event_target: project, author_id: 3) + counter.track_event(event_action: :pushed, event_target: project, author_id: 4, time: time - 3.days) + counter.track_event(event_action: :created, event_target: project, author_id: 5, time: time - 3.days) + counter.track_event(event_action: :created, event_target: wiki, author_id: 3) + counter.track_event(event_action: :created, event_target: design, author_id: 3) end it 'returns the distinct count of user actions within the specified time period' do diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index dfc51ff377b..3eb74da09e1 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -1541,4 +1541,48 @@ RSpec.describe Group do end end end + + describe '#default_owner' do + let(:group) { build(:group) } + + context 'the group has owners' do + before do + group.add_owner(create(:user)) + group.add_owner(create(:user)) + end + + it 'is the first owner' do + expect(group.default_owner) + .to eq(group.owners.first) + .and be_a(User) + end + end + + context 'the group has a parent' do + let(:parent) { build(:group) } + + before do + group.parent = parent + parent.add_owner(create(:user)) + end + + it 'is the first owner of the parent' do + expect(group.default_owner) + .to eq(parent.default_owner) + .and be_a(User) + end + end + + context 'we fallback to group.owner' do + before do + group.owner = build(:user) + end + + it 'is the group.owner' do + expect(group.default_owner) + .to eq(group.owner) + .and be_a(User) + end + end + end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index e6d51e0bfd7..f589589af8f 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1090,6 +1090,30 @@ RSpec.describe Project do end end + describe '#default_owner' do + let_it_be(:owner) { create(:user) } + let_it_be(:namespace) { create(:namespace, owner: owner) } + + context 'the project does not have a group' do + let(:project) { build(:project, namespace: namespace) } + + it 'is the namespace owner' do + expect(project.default_owner).to eq(owner) + end + end + + context 'the project is in a group' do + let(:group) { build(:group) } + let(:project) { build(:project, group: group, namespace: namespace) } + + it 'is the group owner' do + allow(group).to receive(:default_owner).and_return(Object.new) + + expect(project.default_owner).to eq(group.default_owner) + end + end + end + describe '#external_wiki' do let(:project) { create(:project) } diff --git a/spec/models/wiki_spec.rb b/spec/models/wiki_spec.rb new file mode 100644 index 00000000000..8dd510a0b98 --- /dev/null +++ b/spec/models/wiki_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Wiki do + describe '.new' do + it 'verifies that the user is a User' do + expect { described_class.new(double, 1) }.to raise_error(ArgumentError) + expect { described_class.new(double, build(:group)) }.to raise_error(ArgumentError) + expect { described_class.new(double, build(:user)) }.not_to raise_error + expect { described_class.new(double, nil) }.not_to raise_error + end + end +end diff --git a/spec/requests/api/ci/pipelines_spec.rb b/spec/requests/api/ci/pipelines_spec.rb index 6ab00f96092..111bc933ea4 100644 --- a/spec/requests/api/ci/pipelines_spec.rb +++ b/spec/requests/api/ci/pipelines_spec.rb @@ -735,55 +735,36 @@ RSpec.describe API::Ci::Pipelines do let(:pipeline) { create(:ci_pipeline, project: project) } - context 'when feature is enabled' do - before do - stub_feature_flags(junit_pipeline_view: true) - end - - context 'when pipeline does not have a test report' do - it 'returns an empty test report' do - subject - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(0) - end - end - - context 'when pipeline has a test report' do - let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) } - - it 'returns the test report' do - subject + context 'when pipeline does not have a test report' do + it 'returns an empty test report' do + subject - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['total_count']).to eq(4) - end + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['total_count']).to eq(0) end + end - context 'when pipeline has corrupt test reports' do - before do - job = create(:ci_build, pipeline: pipeline) - create(:ci_job_artifact, :junit_with_corrupted_data, job: job, project: project) - end + context 'when pipeline has a test report' do + let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) } - it 'returns a suite_error' do - subject + it 'returns the test report' do + subject - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty') - end + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['total_count']).to eq(4) end end - context 'when feature is disabled' do + context 'when pipeline has corrupt test reports' do before do - stub_feature_flags(junit_pipeline_view: false) + create(:ci_build, :broken_test_reports, name: 'rspec', pipeline: pipeline) end - it 'renders empty response' do + it 'returns a suite_error' do subject - expect(response).to have_gitlab_http_status(:not_found) + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty') end end end diff --git a/spec/services/alert_management/alerts/update_service_spec.rb b/spec/services/alert_management/alerts/update_service_spec.rb index 91b02325bad..ee04fc55984 100644 --- a/spec/services/alert_management/alerts/update_service_spec.rb +++ b/spec/services/alert_management/alerts/update_service_spec.rb @@ -147,8 +147,7 @@ RSpec.describe AlertManagement::Alerts::UpdateService do end it_behaves_like 'does not add a system note' - # TODO: We should not add another todo in this scenario - it_behaves_like 'adds a todo' + it_behaves_like 'does not add a todo' end context 'with multiple users included' do diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb index 57382b7e5a0..edd585cb4b6 100644 --- a/spec/services/event_create_service_spec.rb +++ b/spec/services/event_create_service_spec.rb @@ -207,7 +207,7 @@ RSpec.describe EventCreateService do tracking_params = { event_action: counter_class::WIKI_ACTION, date_from: Date.yesterday, date_to: Date.today } expect { create_event } - .to change { counter_class.count_unique_events(tracking_params) } + .to change { counter_class.count_unique(tracking_params) } .by(1) end end @@ -249,7 +249,7 @@ RSpec.describe EventCreateService do tracking_params = { event_action: counter_class::PUSH_ACTION, date_from: Date.yesterday, date_to: Date.today } expect { subject } - .to change { counter_class.count_unique_events(tracking_params) } + .to change { counter_class.count_unique(tracking_params) } .from(0).to(1) end end @@ -273,7 +273,7 @@ RSpec.describe EventCreateService do tracking_params = { event_action: counter_class::PUSH_ACTION, date_from: Date.yesterday, date_to: Date.today } expect { subject } - .to change { counter_class.count_unique_events(tracking_params) } + .to change { counter_class.count_unique(tracking_params) } .from(0).to(1) end end @@ -328,7 +328,7 @@ RSpec.describe EventCreateService do tracking_params = { event_action: counter_class::DESIGN_ACTION, date_from: Date.yesterday, date_to: Date.today } expect { result } - .to change { counter_class.count_unique_events(tracking_params) } + .to change { counter_class.count_unique(tracking_params) } .from(0).to(1) end end @@ -356,7 +356,7 @@ RSpec.describe EventCreateService do tracking_params = { event_action: counter_class::DESIGN_ACTION, date_from: Date.yesterday, date_to: Date.today } expect { result } - .to change { counter_class.count_unique_events(tracking_params) } + .to change { counter_class.count_unique(tracking_params) } .from(0).to(1) end end diff --git a/spec/services/resource_access_tokens/create_service_spec.rb b/spec/services/resource_access_tokens/create_service_spec.rb index f22c379cd30..7dbd55a6909 100644 --- a/spec/services/resource_access_tokens/create_service_spec.rb +++ b/spec/services/resource_access_tokens/create_service_spec.rb @@ -34,6 +34,16 @@ RSpec.describe ResourceAccessTokens::CreateService do end end + shared_examples 'fails on gitlab.com' do + before do + allow(Gitlab).to receive(:com?) { true } + end + + it 'returns nil' do + expect(subject).to be nil + end + end + shared_examples 'allows creation of bot with valid params' do it { expect { subject }.to change { User.count }.by(1) } @@ -171,6 +181,7 @@ RSpec.describe ResourceAccessTokens::CreateService do it_behaves_like 'fails when user does not have the permission to create a Resource Bot' it_behaves_like 'fails when flag is disabled' + it_behaves_like 'fails on gitlab.com' context 'user with valid permission' do before_all do diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index 13da76263b1..94d4b61933d 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -59,6 +59,10 @@ RSpec.describe TodoService do should_not_create_todo(user: guest, target: addressed_target_assigned, action: Todo::DIRECTLY_ADDRESSED) end + + it 'does not create a todo if already assigned' do + should_not_create_any_todo { service.send(described_method, target_assigned, author, [john_doe]) } + end end describe 'Issues' do @@ -573,10 +577,10 @@ RSpec.describe TodoService do end end - describe '#reassigned_issuable' do - let(:described_method) { :reassigned_issuable } + describe '#reassigned_assignable' do + let(:described_method) { :reassigned_assignable } - context 'issuable is a merge request' do + context 'assignable is a merge request' do it_behaves_like 'reassigned target' do let(:target_assigned) { create(:merge_request, source_project: project, author: author, assignees: [john_doe], description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") } let(:addressed_target_assigned) { create(:merge_request, source_project: project, author: author, assignees: [john_doe], description: "#{directly_addressed}\n- [ ] Task 1\n- [ ] Task 2") } @@ -584,13 +588,21 @@ RSpec.describe TodoService do end end - context 'issuable is an issue' do + context 'assignable is an issue' do it_behaves_like 'reassigned target' do let(:target_assigned) { create(:issue, project: project, author: author, assignees: [john_doe], description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") } let(:addressed_target_assigned) { create(:issue, project: project, author: author, assignees: [john_doe], description: "#{directly_addressed}\n- [ ] Task 1\n- [ ] Task 2") } let(:target_unassigned) { create(:issue, project: project, author: author, assignees: []) } end end + + context 'assignable is an alert' do + it_behaves_like 'reassigned target' do + let(:target_assigned) { create(:alert_management_alert, project: project, assignees: [john_doe]) } + let(:addressed_target_assigned) { create(:alert_management_alert, project: project, assignees: [john_doe]) } + let(:target_unassigned) { create(:alert_management_alert, project: project, assignees: []) } + end + end end describe 'Merge Requests' do @@ -778,16 +790,6 @@ RSpec.describe TodoService do end end - describe '#assign_alert' do - let(:described_method) { :assign_alert } - - it_behaves_like 'reassigned target' do - let(:target_assigned) { create(:alert_management_alert, project: project, assignees: [john_doe]) } - let(:addressed_target_assigned) { create(:alert_management_alert, project: project, assignees: [john_doe]) } - let(:target_unassigned) { create(:alert_management_alert, project: project, assignees: []) } - end - end - describe '#merge_request_build_failed' do let(:merge_participants) { [mr_unassigned.author, admin] } |