diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue b/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue index a2e98502f95..278dcc38c69 100644 --- a/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue +++ b/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue @@ -6,7 +6,6 @@ import JobPill from './job_pill.vue'; import StagePill from './stage_pill.vue'; import { generateLinksData } from './drawing_utils'; import { parseData } from '../parsing_utils'; -import { unwrapArrayOfJobs } from '../unwrapping_utils'; import { DRAW_FAILURE, DEFAULT, INVALID_CI_CONFIG, EMPTY_PIPELINE_DATA } from '../../constants'; import { createJobsHash, generateJobNeedsDict } from '../../utils'; import { CI_CONFIG_STATUS_INVALID } from '~/pipeline_editor/constants'; @@ -136,7 +135,7 @@ export default { methods: { prepareLinkData() { try { - const arrayOfJobs = unwrapArrayOfJobs(this.pipelineStages); + const arrayOfJobs = this.pipelineStages.flatMap(({ groups }) => groups); const parsedData = parseData(arrayOfJobs); this.links = generateLinksData(parsedData, this.$options.CONTAINER_ID); } catch { diff --git a/app/assets/javascripts/pipelines/components/unwrapping_utils.js b/app/assets/javascripts/pipelines/components/unwrapping_utils.js index 285a6f52119..15073079c0a 100644 --- a/app/assets/javascripts/pipelines/components/unwrapping_utils.js +++ b/app/assets/javascripts/pipelines/components/unwrapping_utils.js @@ -1,20 +1,3 @@ -/** - * This function takes the stages and add the stage name - * at the group level as `category` to have an easier - * implementation while constructions nodes with D3 - * @param {Array} stages - * @returns {Array} - Array of stages with stage name at the group level as `category` - */ -export const unwrapArrayOfJobs = (stages = []) => { - return stages - .map(({ name, groups }) => { - return groups.map((group) => { - return { category: name, ...group }; - }); - }) - .flat(2); -}; - const unwrapGroups = (stages) => { return stages.map((stage) => { const { diff --git a/app/models/concerns/issue_available_features.rb b/app/models/concerns/issue_available_features.rb index a9768d93148..a5ffa959174 100644 --- a/app/models/concerns/issue_available_features.rb +++ b/app/models/concerns/issue_available_features.rb @@ -10,7 +10,8 @@ module IssueAvailableFeatures # EE only features are listed on EE::IssueAvailableFeatures def available_features_for_issue_types { - assignee: %w(issue incident) + assignee: %w(issue incident), + confidentiality: %(issue incident) }.with_indifferent_access end end diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml index efe8e57cadf..cc3a5d45153 100644 --- a/app/views/layouts/nav/sidebar/_group.html.haml +++ b/app/views/layouts/nav/sidebar/_group.html.haml @@ -10,6 +10,8 @@ .sidebar-context-title = @group.name %ul.sidebar-top-level-items.qa-group-sidebar + = render_if_exists 'layouts/nav/sidebar/group_trial_status_widget', group: @group + - if group_sidebar_link?(:overview) - paths = group_overview_nav_link_paths = nav_link(path: paths, unless: -> { current_path?('groups/contribution_analytics#show') }, html_options: { class: 'home' }) do diff --git a/changelogs/unreleased/ab-drop-tmp-index.yml b/changelogs/unreleased/ab-drop-tmp-index.yml new file mode 100644 index 00000000000..8be51fe4e0b --- /dev/null +++ b/changelogs/unreleased/ab-drop-tmp-index.yml @@ -0,0 +1,5 @@ +--- +title: Drop temporary index on ci_builds +merge_request: 50961 +author: +type: other diff --git a/db/migrate/20210102164121_drop_temporary_index_on_ci_builds.rb b/db/migrate/20210102164121_drop_temporary_index_on_ci_builds.rb new file mode 100644 index 00000000000..0ecf194eb97 --- /dev/null +++ b/db/migrate/20210102164121_drop_temporary_index_on_ci_builds.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class DropTemporaryIndexOnCiBuilds < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + INDEX = 'tmp_build_stage_position_index'.freeze + + def up + remove_concurrent_index_by_name :ci_builds, INDEX + end + + def down + add_concurrent_index :ci_builds, [:stage_id, :stage_idx], where: 'stage_idx IS NOT NULL', name: INDEX + end +end diff --git a/db/schema_migrations/20210102164121 b/db/schema_migrations/20210102164121 new file mode 100644 index 00000000000..87f9b9e17f4 --- /dev/null +++ b/db/schema_migrations/20210102164121 @@ -0,0 +1 @@ +d15dc3e57f050f037dd6b6b2b1efdafee49bf411580e35a7b4dbe14868c41e13 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index d61338c2983..8105fde4124 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -23105,8 +23105,6 @@ CREATE INDEX temporary_index_vulnerabilities_on_id ON vulnerabilities USING btre CREATE UNIQUE INDEX term_agreements_unique_index ON term_agreements USING btree (user_id, term_id); -CREATE INDEX tmp_build_stage_position_index ON ci_builds USING btree (stage_id, stage_idx) WHERE (stage_idx IS NOT NULL); - CREATE INDEX tmp_index_for_email_unconfirmation_migration ON emails USING btree (id) WHERE (confirmed_at IS NOT NULL); CREATE INDEX tmp_index_on_vulnerabilities_non_dismissed ON vulnerabilities USING btree (id) WHERE (state <> 2); diff --git a/doc/architecture/blueprints/cloud_native_gitlab_pages/index.md b/doc/architecture/blueprints/cloud_native_gitlab_pages/index.md index 95ffcdd0b39..60ddfe8ce02 100644 --- a/doc/architecture/blueprints/cloud_native_gitlab_pages/index.md +++ b/doc/architecture/blueprints/cloud_native_gitlab_pages/index.md @@ -121,9 +121,9 @@ DRIs: | Role | Who |------------------------------|------------------------| -| Product | Jackie Porter | +| Product | Orit Golowinski | | Leadership | Daniel Croft | -| Engineering | Kamil TrzciƄski | +| Engineering | Vladimir Shushlin | Domain Experts: diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-new.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-new.png deleted file mode 100644 index 04d3dc40fa5..00000000000 Binary files a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-new.png and /dev/null differ diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-server.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-server.png deleted file mode 100644 index 63812b41c2c..00000000000 Binary files a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/mix-phoenix-server.png and /dev/null differ diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/pipelines.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/pipelines.png deleted file mode 100644 index c0daa1a6a91..00000000000 Binary files a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/pipelines.png and /dev/null differ diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/select_template_v12_6.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/select_template_v12_6.png deleted file mode 100644 index c8c5e152a13..00000000000 Binary files a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/select_template_v12_6.png and /dev/null differ diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/set_up_ci_v12_6.png b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/set_up_ci_v12_6.png deleted file mode 100644 index fafabb27bac..00000000000 Binary files a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/img/set_up_ci_v12_6.png and /dev/null differ diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md index d1b7883451f..ac5f1a47f9b 100644 --- a/doc/development/testing_guide/best_practices.md +++ b/doc/development/testing_guide/best_practices.md @@ -842,6 +842,41 @@ Example: expect(response).to have_gitlab_http_status(:ok) ``` +#### `match_schema` and `match_response_schema` + +The `match_schema` matcher allows validating that the subject matches a +[JSON schema](https://json-schema.org/). The item inside `expect` can be +a JSON string or a JSON-compatible data structure. + +`match_response_schema` is a convenience matcher for using with a +response object. from a [request +spec](testing_levels.md#integration-tests). + +Examples: + +```ruby +# Matches against spec/fixtures/api/schemas/prometheus/additional_metrics_query_result.json +expect(data).to match_schema('prometheus/additional_metrics_query_result') + +# Matches against ee/spec/fixtures/api/schemas/board.json +expect(data).to match_schema('board', dir: 'ee') + +# Matches against a schema made up of Ruby data structures +expect(data).to match_schema(Atlassian::Schemata.build_info) +``` + +#### `be_valid_json` + +`be_valid_json` allows validating that a string parses as JSON and gives +a non-empty result. To combine it with the schema matching above, use +`and`: + +```ruby +expect(json_string).to be_valid_json + +expect(json_string).to be_valid_json.and match_schema(schema) +``` + ### Testing query performance Testing query performance allows us to: diff --git a/doc/user/admin_area/license.md b/doc/user/admin_area/license.md index 2f2fac04475..d06b0c844ec 100644 --- a/doc/user/admin_area/license.md +++ b/doc/user/admin_area/license.md @@ -53,10 +53,10 @@ Otherwise, you can: ![Upload license](img/license_upload_v13_8.png) - *If you've received your license as plain text:* - 1. Select **Enter license key**. - 1. Copy the license and paste it into the **License key** field. - 1. Check the **Subscription Agreement** checkbox. - 1. Select **Upload License**. + 1. Select **Enter license key**. + 1. Copy the license and paste it into the **License key** field. + 1. Check the **Subscription Agreement** checkbox. + 1. Select **Upload License**. ## Add your license at install time diff --git a/doc/user/infrastructure/mr_integration.md b/doc/user/infrastructure/mr_integration.md index c86e5ddf1db..2704e7b7c8d 100644 --- a/doc/user/infrastructure/mr_integration.md +++ b/doc/user/infrastructure/mr_integration.md @@ -72,10 +72,10 @@ To manually configure a GitLab Terraform Report artifact requires the following terraform: $PLAN_JSON ``` - For a full example using the pre-built image, see [Example `.gitlab-ci.yaml` - file](#example-gitlab-ciyaml-file). + For a full example using the pre-built image, see [Example `.gitlab-ci.yml` + file](#example-gitlab-ciyml-file). - For an example displaying multiple reports, see [`.gitlab-ci.yaml` multiple reports file](#multiple-terraform-plan-reports). + For an example displaying multiple reports, see [`.gitlab-ci.yml` multiple reports file](#multiple-terraform-plan-reports). 1. Running the pipeline displays the widget in the merge request, like this: @@ -86,7 +86,7 @@ To manually configure a GitLab Terraform Report artifact requires the following ![Terraform plan logs](img/terraform_plan_log_v13_0.png) -### Example `.gitlab-ci.yaml` file +### Example `.gitlab-ci.yml` file ```yaml default: diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md index 06b614f877a..90d7ac0a3c2 100644 --- a/doc/user/project/releases/index.md +++ b/doc/user/project/releases/index.md @@ -200,7 +200,7 @@ If the job that's executing is within a freeze period, GitLab CI/CD creates an e variable named `$CI_DEPLOY_FREEZE`. To prevent the deployment job from executing, create a `rules` entry in your -`gitlab-ci.yaml`, for example: +`gitlab-ci.yml`, for example: ```yaml deploy_to_production: diff --git a/lib/gitlab/experimentation.rb b/lib/gitlab/experimentation.rb index 2c84f8df4f0..196203211ed 100644 --- a/lib/gitlab/experimentation.rb +++ b/lib/gitlab/experimentation.rb @@ -100,6 +100,9 @@ module Gitlab invite_members_new_dropdown: { tracking_category: 'Growth::Expansion::Experiment::InviteMembersNewDropdown' }, + show_trial_status_in_sidebar: { + tracking_category: 'Growth::Conversion::Experiment::ShowTrialStatusInSidebar' + }, trial_onboarding_issues: { tracking_category: 'Growth::Conversion::Experiment::TrialOnboardingIssues' } diff --git a/lib/gitlab/quick_actions/issue_actions.rb b/lib/gitlab/quick_actions/issue_actions.rb index 1822b0c8bd5..c162ee545c6 100644 --- a/lib/gitlab/quick_actions/issue_actions.rb +++ b/lib/gitlab/quick_actions/issue_actions.rb @@ -170,7 +170,8 @@ module Gitlab end types Issue condition do - !quick_action_target.confidential? && + quick_action_target.issue_type_supports?(:confidentiality) && + !quick_action_target.confidential? && current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target) end command :confidential do diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 7ea1eeb1360..e1fff1aef93 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -29638,6 +29638,11 @@ msgstr "" msgid "Trending" msgstr "" +msgid "Trials|%{plan} Trial %{en_dash} %{num} day left" +msgid_plural "Trials|%{plan} Trial %{en_dash} %{num} days left" +msgstr[0] "" +msgstr[1] "" + msgid "Trials|Create a new group to start your GitLab Gold trial." msgstr "" diff --git a/spec/frontend/pipelines/unwrapping_utils_spec.js b/spec/frontend/pipelines/unwrapping_utils_spec.js index 853bc37e9df..cd16ed7262e 100644 --- a/spec/frontend/pipelines/unwrapping_utils_spec.js +++ b/spec/frontend/pipelines/unwrapping_utils_spec.js @@ -1,5 +1,4 @@ import { - unwrapArrayOfJobs, unwrapGroups, unwrapNodesWithName, unwrapStagesWithNeeds, @@ -95,29 +94,6 @@ const completeMock = [ ]; describe('Shared pipeline unwrapping utils', () => { - describe('unwrapArrayOfJobs', () => { - it('returns an empty array if the input is an empty undefined', () => { - expect(unwrapArrayOfJobs(undefined)).toEqual([]); - }); - - it('returns an empty array if the input is an empty array', () => { - expect(unwrapArrayOfJobs([])).toEqual([]); - }); - - it('returns a flatten array of each job with their data and stage name', () => { - expect( - unwrapArrayOfJobs([ - { name: 'build', groups: [{ name: 'job_a_1' }, { name: 'job_a_2' }] }, - { name: 'test', groups: [{ name: 'job_b' }] }, - ]), - ).toMatchObject([ - { category: 'build', name: 'job_a_1' }, - { category: 'build', name: 'job_a_2' }, - { category: 'test', name: 'job_b' }, - ]); - }); - }); - describe('unwrapGroups', () => { it('takes stages without nodes and returns the unwrapped groups', () => { expect(unwrapGroups(stagesAndGroups)[0].groups).toEqual(groupsArray); diff --git a/spec/lib/atlassian/jira_connect/client_spec.rb b/spec/lib/atlassian/jira_connect/client_spec.rb index 7c05912a49d..9759bceb58e 100644 --- a/spec/lib/atlassian/jira_connect/client_spec.rb +++ b/spec/lib/atlassian/jira_connect/client_spec.rb @@ -114,7 +114,7 @@ RSpec.describe Atlassian::JiraConnect::Client do end let(:body) do - matcher = be_valid_json.according_to_schema(schema) + matcher = be_valid_json.and match_schema(schema) ->(text) { matcher.matches?(text) } end @@ -164,7 +164,7 @@ RSpec.describe Atlassian::JiraConnect::Client do end let(:body) do - matcher = be_valid_json.according_to_schema(build_info_payload_schema) + matcher = be_valid_json.and match_schema(build_info_payload_schema) ->(text) { matcher.matches?(text) } end diff --git a/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb b/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb index 52e475d20ca..4bbd654655d 100644 --- a/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb +++ b/spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb @@ -23,7 +23,7 @@ RSpec.describe Atlassian::JiraConnect::Serializers::BuildEntity do end it 'is invalid, since it has no issue keys' do - expect(subject.to_json).not_to be_valid_json.according_to_schema(Atlassian::Schemata.build_info) + expect(subject.to_json).not_to match_schema(Atlassian::Schemata.build_info) end end end @@ -43,7 +43,7 @@ RSpec.describe Atlassian::JiraConnect::Serializers::BuildEntity do describe '#to_json' do it 'is valid according to the build info schema' do - expect(subject.to_json).to be_valid_json.according_to_schema(Atlassian::Schemata.build_info) + expect(subject.to_json).to be_valid_json.and match_schema(Atlassian::Schemata.build_info) end end end diff --git a/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb b/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb index 42a10944dc9..82bcbdc4561 100644 --- a/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb +++ b/spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb @@ -23,7 +23,7 @@ RSpec.describe Atlassian::JiraConnect::Serializers::DeploymentEntity do end it 'is invalid, since it has no issue keys' do - expect(subject.to_json).not_to be_valid_json.according_to_schema(Atlassian::Schemata.deployment_info) + expect(subject.to_json).not_to match_schema(Atlassian::Schemata.deployment_info) end end end @@ -86,7 +86,7 @@ RSpec.describe Atlassian::JiraConnect::Serializers::DeploymentEntity do describe '#to_json' do it 'is valid according to the deployment info schema' do - expect(subject.to_json).to be_valid_json.according_to_schema(Atlassian::Schemata.deployment_info) + expect(subject.to_json).to be_valid_json.and match_schema(Atlassian::Schemata.deployment_info) end end end diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index fb993a1ce17..c80fafe1c5d 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -1142,6 +1142,11 @@ RSpec.describe QuickActions::InterpretService do let(:issuable) { issue } end + it_behaves_like 'confidential command' do + let(:content) { '/confidential' } + let(:issuable) { create(:incident, project: project) } + end + it_behaves_like 'lock command' do let(:content) { '/lock' } let(:issuable) { issue } diff --git a/spec/support/matchers/be_valid_json.rb b/spec/support/matchers/be_valid_json.rb index f46c35c7198..228c1fc986e 100644 --- a/spec/support/matchers/be_valid_json.rb +++ b/spec/support/matchers/be_valid_json.rb @@ -1,20 +1,8 @@ # frozen_string_literal: true RSpec::Matchers.define :be_valid_json do - def according_to_schema(schema) - @schema = schema - self - end - match do |actual| - data = Gitlab::Json.parse(actual) - - if @schema.present? - @validation_errors = JSON::Validator.fully_validate(@schema, data) - @validation_errors.empty? - else - data.present? - end + Gitlab::Json.parse(actual).present? rescue JSON::ParserError => e @error = e false @@ -23,8 +11,6 @@ RSpec::Matchers.define :be_valid_json do def failure_message if @error "Parse failed with error: #{@error}" - elsif @validation_errors.present? - "Validation failed because #{@validation_errors.join(', and ')}" else "Parsing did not return any data" end diff --git a/spec/support/matchers/schema_matcher.rb b/spec/support/matchers/schema_matcher.rb index ebbd57c8115..a7696a511bd 100644 --- a/spec/support/matchers/schema_matcher.rb +++ b/spec/support/matchers/schema_matcher.rb @@ -2,6 +2,8 @@ module SchemaPath def self.expand(schema, dir = nil) + return schema unless schema.is_a?(String) + if Gitlab.ee? && dir.nil? ee_path = expand(schema, 'ee')