summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-02-25 00:11:24 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-25 00:11:24 +0000
commitcffcf0772c5354d0d55fd4e32f724108a9582f15 (patch)
treeac827ac27f31b41f9e05d4ffe757be9f54aa6578
parent1631d8a2e0eef291f1d0b9486ee35ed6b52a176a (diff)
downloadgitlab-ce-cffcf0772c5354d0d55fd4e32f724108a9582f15.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--Gemfile.lock2
-rw-r--r--app/assets/javascripts/issues_list/components/issuable.vue25
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/edit/index.js6
-rw-r--r--app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue4
-rw-r--r--changelogs/unreleased/267511-approval-gate-rule-type.yml5
-rw-r--r--changelogs/unreleased/322724-fix-compare-page-dropdown-loading.yml5
-rw-r--r--changelogs/unreleased/fix-web-url-jira.yml5
-rw-r--r--config/metrics/schema.json2
-rw-r--r--db/migrate/20210209110019_create_external_approval_rules.rb44
-rw-r--r--db/migrate/20210223132934_add_foreign_key_to_external_approval_rules.rb18
-rw-r--r--db/migrate/20210223133116_add_foreign_key_to_external_approval_rules_protected_branches.rb18
-rw-r--r--db/schema_migrations/202102091100191
-rw-r--r--db/schema_migrations/202102231329341
-rw-r--r--db/schema_migrations/202102231331161
-rw-r--r--db/structure.sql62
-rw-r--r--doc/api/merge_request_approvals.md85
-rw-r--r--doc/ci/metrics_reports.md10
-rw-r--r--doc/development/usage_ping/metrics_dictionary.md2
-rw-r--r--doc/integration/bitbucket.md9
-rw-r--r--doc/integration/github.md13
-rw-r--r--doc/topics/autodevops/index.md8
-rw-r--r--spec/factories/alert_management/alerts.rb6
-rw-r--r--spec/factories/prometheus_alert_event.rb5
-rw-r--r--spec/factories/self_managed_prometheus_alert_event.rb11
-rw-r--r--spec/factories_spec.rb4
-rw-r--r--spec/frontend/issues_list/components/issuable_spec.js31
-rw-r--r--spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js14
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/models/prometheus_alert_event_spec.rb2
29 files changed, 341 insertions, 59 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index fa319de1076..3309a317645 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -443,7 +443,7 @@ GEM
jaeger-client (~> 1.1)
opentracing (~> 0.4)
redis (> 3.0.0, < 5.0.0)
- gitlab-license (1.3.0)
+ gitlab-license (1.3.1)
gitlab-mail_room (0.0.8)
gitlab-markup (1.7.1)
gitlab-net-dns (0.9.1)
diff --git a/app/assets/javascripts/issues_list/components/issuable.vue b/app/assets/javascripts/issues_list/components/issuable.vue
index b7af6e098e1..a2970bdc43b 100644
--- a/app/assets/javascripts/issues_list/components/issuable.vue
+++ b/app/assets/javascripts/issues_list/components/issuable.vue
@@ -25,7 +25,7 @@ import {
newDateAsLocaleTime,
} from '~/lib/utils/datetime_utility';
import { convertToCamelCase } from '~/lib/utils/text_utility';
-import { mergeUrlParams } from '~/lib/utils/url_utility';
+import { mergeUrlParams, setUrlFragment, isExternal } from '~/lib/utils/url_utility';
import { sprintf, __ } from '~/locale';
import initUserPopovers from '~/user_popovers';
import IssueAssignees from '~/vue_shared/components/issue/issue_assignees.vue';
@@ -102,8 +102,14 @@ export default {
isJiraIssue() {
return this.issuable.external_tracker === 'jira';
},
+ webUrl() {
+ return this.issuable.gitlab_web_url || this.issuable.web_url;
+ },
+ isIssuableUrlExternal() {
+ return isExternal(this.webUrl);
+ },
linkTarget() {
- return this.isJiraIssue ? '_blank' : null;
+ return this.isIssuableUrlExternal ? '_blank' : null;
},
issueCreatedToday() {
return getDayDifference(new Date(this.issuable.created_at), new Date()) < 1;
@@ -188,7 +194,7 @@ export default {
value: this.issuable.blocking_issues_count,
title: __('Blocking issues'),
dataTestId: 'blocking-issues',
- href: `${this.issuable.web_url}#related-issues`,
+ href: setUrlFragment(this.webUrl, 'related-issues'),
icon: 'issue-block',
},
{
@@ -197,7 +203,7 @@ export default {
value: this.issuable.user_notes_count,
title: __('Comments'),
dataTestId: 'notes-count',
- href: `${this.issuable.web_url}#notes`,
+ href: setUrlFragment(this.webUrl, 'notes'),
class: { 'no-comments': !this.issuable.user_notes_count, 'issuable-comments': true },
icon: 'comments',
},
@@ -252,7 +258,7 @@ export default {
:class="{ today: issueCreatedToday, closed: isClosed }"
:data-id="issuable.id"
:data-labels="labelIdsString"
- :data-url="issuable.web_url"
+ :data-url="webUrl"
data-qa-selector="issue_container"
:data-qa-issue-title="issuable.title"
>
@@ -284,13 +290,14 @@ export default {
:aria-label="$options.confidentialTooltipText"
/>
<gl-link
- :href="issuable.web_url"
+ :href="webUrl"
:target="linkTarget"
data-testid="issuable-title"
data-qa-selector="issue_link"
- >{{ issuable.title
- }}<gl-icon
- v-if="isJiraIssue"
+ >
+ {{ issuable.title }}
+ <gl-icon
+ v-if="isIssuableUrlExternal"
name="external-link"
class="gl-vertical-align-text-bottom gl-ml-2"
/>
diff --git a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
index 399aebb0c83..ec21d8c84e0 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
@@ -1,7 +1,5 @@
import initMergeRequest from '~/pages/projects/merge_requests/init_merge_request';
import initCheckFormState from './check_form_state';
-document.addEventListener('DOMContentLoaded', () => {
- initMergeRequest();
- initCheckFormState();
-});
+initMergeRequest();
+initCheckFormState();
diff --git a/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue b/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue
index a5e2c986b12..13d80b5ae0b 100644
--- a/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue
+++ b/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue
@@ -65,8 +65,8 @@ export default {
return axios
.get(endpoint)
.then(({ data }) => {
- this.branches = data.Branches;
- this.tags = data.Tags;
+ this.branches = data.Branches || [];
+ this.tags = data.Tags || [];
})
.catch(() => {
createFlash({
diff --git a/changelogs/unreleased/267511-approval-gate-rule-type.yml b/changelogs/unreleased/267511-approval-gate-rule-type.yml
new file mode 100644
index 00000000000..ebc2a7d80aa
--- /dev/null
+++ b/changelogs/unreleased/267511-approval-gate-rule-type.yml
@@ -0,0 +1,5 @@
+---
+title: Create ExternalApprovalRule table and associations
+merge_request: 54002
+author:
+type: added
diff --git a/changelogs/unreleased/322724-fix-compare-page-dropdown-loading.yml b/changelogs/unreleased/322724-fix-compare-page-dropdown-loading.yml
new file mode 100644
index 00000000000..42359bb81d2
--- /dev/null
+++ b/changelogs/unreleased/322724-fix-compare-page-dropdown-loading.yml
@@ -0,0 +1,5 @@
+---
+title: Fix issue with loading the repository compare page
+merge_request: 55058
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-web-url-jira.yml b/changelogs/unreleased/fix-web-url-jira.yml
new file mode 100644
index 00000000000..0a0b973bb84
--- /dev/null
+++ b/changelogs/unreleased/fix-web-url-jira.yml
@@ -0,0 +1,5 @@
+---
+title: Use gitlab_web_url (if it exists) for issue title links in Issue lists
+merge_request: 55021
+author:
+type: fixed
diff --git a/config/metrics/schema.json b/config/metrics/schema.json
index 53e52c21545..621c7884c67 100644
--- a/config/metrics/schema.json
+++ b/config/metrics/schema.json
@@ -26,7 +26,7 @@
},
"status": {
"type": ["string"],
- "enum": ["data_available", "planned", "in_progress", "implemented"]
+ "enum": ["data_available", "planned", "in_progress", "implemented", "not_used", "deprecated"]
},
"milestone": {
"type": ["number", "null"]
diff --git a/db/migrate/20210209110019_create_external_approval_rules.rb b/db/migrate/20210209110019_create_external_approval_rules.rb
new file mode 100644
index 00000000000..5d6780ec412
--- /dev/null
+++ b/db/migrate/20210209110019_create_external_approval_rules.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+class CreateExternalApprovalRules < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+ disable_ddl_transaction!
+
+ DOWNTIME = false
+
+ def up
+ create_table_with_constraints :external_approval_rules, if_not_exists: true do |t|
+ t.references :project, foreign_key: { on_delete: :cascade }, null: false, index: false
+ t.timestamps_with_timezone
+ t.text :external_url, null: false
+ t.text_limit :external_url, 255
+ t.text :name, null: false
+ t.text_limit :name, 255
+
+ t.index([:project_id, :name],
+ unique: true,
+ name: 'idx_on_external_approval_rules_project_id_name')
+ t.index([:project_id, :external_url],
+ unique: true,
+ name: 'idx_on_external_approval_rules_project_id_external_url')
+ end
+
+ create_table :external_approval_rules_protected_branches do |t|
+ t.bigint :external_approval_rule_id, null: false, index: { name: 'idx_eaprpb_external_approval_rule_id' }
+ t.bigint :protected_branch_id, null: false
+ t.index([:protected_branch_id, :external_approval_rule_id],
+ unique: true,
+ name: 'idx_protected_branch_id_external_approval_rule_id')
+ end
+ end
+
+ def down
+ with_lock_retries do
+ drop_table :external_approval_rules_protected_branches, force: :cascade, if_exists: true
+ end
+
+ with_lock_retries do
+ drop_table :external_approval_rules, force: :cascade, if_exists: true
+ end
+ end
+end
diff --git a/db/migrate/20210223132934_add_foreign_key_to_external_approval_rules.rb b/db/migrate/20210223132934_add_foreign_key_to_external_approval_rules.rb
new file mode 100644
index 00000000000..b5f04672813
--- /dev/null
+++ b/db/migrate/20210223132934_add_foreign_key_to_external_approval_rules.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddForeignKeyToExternalApprovalRules < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :external_approval_rules_protected_branches, :external_approval_rules, column: :external_approval_rule_id, on_delete: :cascade
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :external_approval_rules_protected_branches, column: :external_approval_rule_id
+ end
+ end
+end
diff --git a/db/migrate/20210223133116_add_foreign_key_to_external_approval_rules_protected_branches.rb b/db/migrate/20210223133116_add_foreign_key_to_external_approval_rules_protected_branches.rb
new file mode 100644
index 00000000000..ad51f765d8a
--- /dev/null
+++ b/db/migrate/20210223133116_add_foreign_key_to_external_approval_rules_protected_branches.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddForeignKeyToExternalApprovalRulesProtectedBranches < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :external_approval_rules_protected_branches, :protected_branches, column: :protected_branch_id, on_delete: :cascade
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :external_approval_rules_protected_branches, column: :protected_branch_id
+ end
+ end
+end
diff --git a/db/schema_migrations/20210209110019 b/db/schema_migrations/20210209110019
new file mode 100644
index 00000000000..d11e6e5a167
--- /dev/null
+++ b/db/schema_migrations/20210209110019
@@ -0,0 +1 @@
+a24354264df3c12411af040903d26faf298f06a7334ef118f87b3e88b683b326 \ No newline at end of file
diff --git a/db/schema_migrations/20210223132934 b/db/schema_migrations/20210223132934
new file mode 100644
index 00000000000..6e2b0696bad
--- /dev/null
+++ b/db/schema_migrations/20210223132934
@@ -0,0 +1 @@
+99ee6773319af0fa7a1dfef92f67cc95141c892bf7adcf500d46adc1ebd4c70f \ No newline at end of file
diff --git a/db/schema_migrations/20210223133116 b/db/schema_migrations/20210223133116
new file mode 100644
index 00000000000..235053e8fe8
--- /dev/null
+++ b/db/schema_migrations/20210223133116
@@ -0,0 +1 @@
+991041c8d3092175165834a988eb32141e49d7785cda756c8a78170b4af6db64 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index c3b46a15098..08d79ddf007 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -12349,6 +12349,41 @@ CREATE SEQUENCE experiments_id_seq
ALTER SEQUENCE experiments_id_seq OWNED BY experiments.id;
+CREATE TABLE external_approval_rules (
+ id bigint NOT NULL,
+ project_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ external_url text NOT NULL,
+ name text NOT NULL,
+ CONSTRAINT check_1c64b53ea5 CHECK ((char_length(name) <= 255)),
+ CONSTRAINT check_b634ca168d CHECK ((char_length(external_url) <= 255))
+);
+
+CREATE SEQUENCE external_approval_rules_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE external_approval_rules_id_seq OWNED BY external_approval_rules.id;
+
+CREATE TABLE external_approval_rules_protected_branches (
+ id bigint NOT NULL,
+ external_approval_rule_id bigint NOT NULL,
+ protected_branch_id bigint NOT NULL
+);
+
+CREATE SEQUENCE external_approval_rules_protected_branches_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE external_approval_rules_protected_branches_id_seq OWNED BY external_approval_rules_protected_branches.id;
+
CREATE TABLE external_pull_requests (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -18995,6 +19030,10 @@ ALTER TABLE ONLY experiment_users ALTER COLUMN id SET DEFAULT nextval('experimen
ALTER TABLE ONLY experiments ALTER COLUMN id SET DEFAULT nextval('experiments_id_seq'::regclass);
+ALTER TABLE ONLY external_approval_rules ALTER COLUMN id SET DEFAULT nextval('external_approval_rules_id_seq'::regclass);
+
+ALTER TABLE ONLY external_approval_rules_protected_branches ALTER COLUMN id SET DEFAULT nextval('external_approval_rules_protected_branches_id_seq'::regclass);
+
ALTER TABLE ONLY external_pull_requests ALTER COLUMN id SET DEFAULT nextval('external_pull_requests_id_seq'::regclass);
ALTER TABLE ONLY feature_gates ALTER COLUMN id SET DEFAULT nextval('feature_gates_id_seq'::regclass);
@@ -20219,6 +20258,12 @@ ALTER TABLE ONLY experiment_users
ALTER TABLE ONLY experiments
ADD CONSTRAINT experiments_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY external_approval_rules
+ ADD CONSTRAINT external_approval_rules_pkey PRIMARY KEY (id);
+
+ALTER TABLE ONLY external_approval_rules_protected_branches
+ ADD CONSTRAINT external_approval_rules_protected_branches_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY external_pull_requests
ADD CONSTRAINT external_pull_requests_pkey PRIMARY KEY (id);
@@ -21317,6 +21362,8 @@ CREATE INDEX idx_container_repositories_on_exp_cleanup_status_and_start_date ON
CREATE INDEX idx_deployment_clusters_on_cluster_id_and_kubernetes_namespace ON deployment_clusters USING btree (cluster_id, kubernetes_namespace);
+CREATE INDEX idx_eaprpb_external_approval_rule_id ON external_approval_rules_protected_branches USING btree (external_approval_rule_id);
+
CREATE UNIQUE INDEX idx_environment_merge_requests_unique_index ON deployment_merge_requests USING btree (environment_id, merge_request_id);
CREATE INDEX idx_geo_con_rep_updated_events_on_container_repository_id ON geo_container_repository_updated_events USING btree (container_repository_id);
@@ -21357,6 +21404,10 @@ CREATE INDEX idx_mr_cc_diff_files_on_mr_cc_id_and_sha ON merge_request_context_c
CREATE UNIQUE INDEX idx_on_compliance_management_frameworks_namespace_id_name ON compliance_management_frameworks USING btree (namespace_id, name);
+CREATE UNIQUE INDEX idx_on_external_approval_rules_project_id_external_url ON external_approval_rules USING btree (project_id, external_url);
+
+CREATE UNIQUE INDEX idx_on_external_approval_rules_project_id_name ON external_approval_rules USING btree (project_id, name);
+
CREATE INDEX idx_packages_build_infos_on_package_id ON packages_build_infos USING btree (package_id);
CREATE INDEX idx_packages_debian_group_component_files_on_architecture_id ON packages_debian_group_component_files USING btree (architecture_id);
@@ -21385,6 +21436,8 @@ CREATE INDEX idx_projects_id_created_at_disable_overriding_approvers_true ON pro
CREATE INDEX idx_projects_on_repository_storage_last_repository_updated_at ON projects USING btree (id, repository_storage, last_repository_updated_at);
+CREATE UNIQUE INDEX idx_protected_branch_id_external_approval_rule_id ON external_approval_rules_protected_branches USING btree (protected_branch_id, external_approval_rule_id);
+
CREATE INDEX idx_repository_states_on_last_repository_verification_ran_at ON project_repository_states USING btree (project_id, last_repository_verification_ran_at) WHERE ((repository_verification_checksum IS NOT NULL) AND (last_repository_verification_failure IS NULL));
CREATE INDEX idx_repository_states_on_last_wiki_verification_ran_at ON project_repository_states USING btree (project_id, last_wiki_verification_ran_at) WHERE ((wiki_verification_checksum IS NOT NULL) AND (last_wiki_verification_failure IS NULL));
@@ -24695,6 +24748,12 @@ ALTER TABLE ONLY issues
ALTER TABLE ONLY issue_links
ADD CONSTRAINT fk_c900194ff2 FOREIGN KEY (source_id) REFERENCES issues(id) ON DELETE CASCADE;
+ALTER TABLE ONLY external_approval_rules_protected_branches
+ ADD CONSTRAINT fk_c9a037a926 FOREIGN KEY (external_approval_rule_id) REFERENCES external_approval_rules(id) ON DELETE CASCADE;
+
+ALTER TABLE ONLY external_approval_rules_protected_branches
+ ADD CONSTRAINT fk_ca2ffb55e6 FOREIGN KEY (protected_branch_id) REFERENCES protected_branches(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY experiment_subjects
ADD CONSTRAINT fk_ccc28f8ceb FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -26309,6 +26368,9 @@ ALTER TABLE ONLY ci_job_variables
ALTER TABLE ONLY packages_nuget_metadata
ADD CONSTRAINT fk_rails_fc0c19f5b4 FOREIGN KEY (package_id) REFERENCES packages_packages(id) ON DELETE CASCADE;
+ALTER TABLE ONLY external_approval_rules
+ ADD CONSTRAINT fk_rails_fd4f9ac573 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY experiment_users
ADD CONSTRAINT fk_rails_fd805f771a FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md
index 5b8bad1d685..86bc56b7149 100644
--- a/doc/api/merge_request_approvals.md
+++ b/doc/api/merge_request_approvals.md
@@ -567,6 +567,91 @@ PUT /projects/:id/approvers
}
```
+## External Project-level MR approvals **(ULTIMATE)**
+
+Configuration for approvals on a specific Merge Request which makes a call to an external HTTP resource.
+
+> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3869) in GitLab 13.10.
+> - 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-external-project-level-mr-approvals). **(ULTIMATE SELF)**
+
+### Get project external approval rules **(ULTIMATE)**
+
+You can request information about a project's external approval rules using the following endpoint:
+
+```plaintext
+GET /projects/:id/external_approval_rules
+```
+
+**Parameters:**
+
+| Attribute | Type | Required | Description |
+|---------------------|---------|----------|---------------------|
+| `id` | integer | yes | The ID of a project |
+
+```json
+[
+ {
+ "id": 1,
+ "name": "Compliance Check",
+ "project_id": 6,
+ "external_url": "https://gitlab.com/example/test.json",
+ "protected_branches": [
+ {
+ "id": 14,
+ "project_id": 6,
+ "name": "master",
+ "created_at": "2020-10-12T14:04:50.787Z",
+ "updated_at": "2020-10-12T14:04:50.787Z",
+ "code_owner_approval_required": false
+ }
+ ]
+ }
+]
+```
+
+### Create external approval rule **(ULTIMATE)**
+
+You can create a new external approval rule for a project using the following endpoint:
+
+```plaintext
+POST /projects/:id/external_approval_rules
+```
+
+| Attribute | Type | Required | Description |
+|------------------------|----------------|----------|----------------------------------------------------|
+| `id` | integer | yes | The ID of a project |
+| `name` | string | yes | Display name of approval rule |
+| `external_url` | string | yes | URL of external approval resource |
+| `protected_branch_ids` | array<Integer> | no | The ids of protected branches to scope the rule by |
+
+### Enable or disable External Project-level MR approvals **(ULTIMATE SELF)**
+
+Enable or disable External Project-level MR approvals is under development and not ready for production use. It is
+deployed behind a feature flag that is **disabled by default**.
+[GitLab administrators with access to the GitLab Rails console](../user/feature_flags.md)
+can enable it.
+
+To enable it:
+
+```ruby
+# For the instance
+Feature.enable(:ff_compliance_approval_gates)
+# For a single project
+Feature.enable(:ff_compliance_approval_gates, Project.find(<project id>))
+```
+
+To disable it:
+
+```ruby
+# For the instance
+Feature.disable(:ff_compliance_approval_gates)
+# For a single project
+Feature.disable(:ff_compliance_approval_gates, Project.find(<project id>))
+```
+
## Merge Request-level MR approvals
Configuration for approvals on a specific Merge Request. Must be authenticated for all endpoints.
diff --git a/doc/ci/metrics_reports.md b/doc/ci/metrics_reports.md
index 3966e5e3e89..716959143ef 100644
--- a/doc/ci/metrics_reports.md
+++ b/doc/ci/metrics_reports.md
@@ -26,12 +26,14 @@ Consider the following examples of data that can use Metrics Reports:
## How it works
-Metrics are read from the metrics report (default: `metrics.txt`). They are parsed and displayed in the MR widget.
+Metrics for a branch are read from the latest metrics report artifact (default filename: `metrics.txt`) as string values.
-All values are considered strings and string compare is used to find differences between the latest available `metrics` artifact from:
+For an MR, the values of these metrics from the feature branch are compared to the values from the target branch. Then they are displayed in the MR widget in this order:
-- `master`
-- The feature branch
+- Metrics that have been added by the MR. Marked with a **New** badge.
+- Existing metrics with changed values.
+- Existing metrics with unchanged values.
+- Metrics that have been removed by the MR. Marked with a **Removed** badge.
## How to set it up
diff --git a/doc/development/usage_ping/metrics_dictionary.md b/doc/development/usage_ping/metrics_dictionary.md
index 9f98671050c..f27e258a9c2 100644
--- a/doc/development/usage_ping/metrics_dictionary.md
+++ b/doc/development/usage_ping/metrics_dictionary.md
@@ -33,7 +33,7 @@ Each metric is defined in a separate YAML file consisting of a number of fields:
| `product_group` | yes | The [group](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) that owns the metric. |
| `product_category` | no | The [product category](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml) for the metric. |
| `value_type` | yes | `string`; one of `string`, `number`, `boolean`. |
-| `status` | yes | `string`; status of the metric, may be set to `data_available`, `implemented`. |
+| `status` | yes | `string`; status of the metric, may be set to `data_available`, `planned`, `in_progress`, `implemented`, `not_used`, `deprecated` |
| `time_frame` | yes | `string`; may be set to a value like `7d`, `28d`, `all`, `none`. |
| `data_source` | yes | `string`: may be set to a value like `database`, `redis`, `redis_hll`, `prometheus`, `ruby`. |
| `distribution` | yes | The [distribution](https://about.gitlab.com/handbook/marketing/strategic-marketing/tiers/#definitions) where the metric applies. |
diff --git a/doc/integration/bitbucket.md b/doc/integration/bitbucket.md
index 54bcaee7cab..a492b891248 100644
--- a/doc/integration/bitbucket.md
+++ b/doc/integration/bitbucket.md
@@ -26,6 +26,11 @@ To enable the Bitbucket OmniAuth provider you must register your application
with Bitbucket.org. Bitbucket generates an application ID and secret key for
you to use.
+WARNING:
+To help prevent an [OAuth 2 covert redirect](https://oauth.net/advisories/2014-1-covert-redirect/)
+vulnerability in which users' GitLab accounts could be compromised, append `/users/auth`
+to the end of the Bitbucket authorization callback URL.
+
1. Sign in to [Bitbucket.org](https://bitbucket.org).
1. Navigate to your individual user settings (**Bitbucket settings**) or a team's
settings (**Manage team**), depending on how you want the application registered.
@@ -40,9 +45,7 @@ you to use.
- **Application description:** *(Optional)* Fill this in if you wish.
- **Callback URL:** (Required in GitLab versions 8.15 and greater)
The URL to your GitLab installation, such as
- `https://gitlab.example.com/users/auth`. Be sure to append `/users/auth` to
- the end of the callback URL to prevent an
- [OAuth2 convert redirect](http://tetraph.com/covert_redirect/) vulnerability.
+ `https://gitlab.example.com/users/auth`.
Leaving this field empty
[results in an `Invalid redirect_uri` message](https://confluence.atlassian.com/bitbucket/oauth-faq-338365710.html).
- **URL:** The URL to your GitLab installation, such as `https://gitlab.example.com`.
diff --git a/doc/integration/github.md b/doc/integration/github.md
index 4258b1c3c76..4d8adfe42f1 100644
--- a/doc/integration/github.md
+++ b/doc/integration/github.md
@@ -10,6 +10,16 @@ You can integrate your GitLab instance with GitHub.com and GitHub Enterprise. Th
enables users to import projects from GitHub, or sign in to your GitLab instance
with their GitHub account.
+## Security check
+
+Some integrations risk compromising GitLab accounts. To help mitigate this
+[OAuth 2 covert redirect](https://oauth.net/advisories/2014-1-covert-redirect/)
+vulnerability, append `/users/auth` to the end of the authorization callback URL.
+
+However, as far as we know, GitHub does not validate the subdomain part of the `redirect_uri`.
+This means that a subdomain takeover, an XSS, or an open redirect on any subdomain of
+your website could enable the covert redirect attack.
+
## Enabling GitHub OAuth
To enable the GitHub OmniAuth provider, you need an OAuth 2 Client ID and Client Secret from GitHub. To get these credentials, sign into GitHub and follow their procedure for [Creating an OAuth App](https://docs.github.com/en/developers/apps/creating-an-oauth-app).
@@ -19,9 +29,6 @@ When you create an OAuth 2 app in GitHub, you need the following information:
- The URL of your GitLab instance, such as `https://gitlab.example.com`.
- The authorization callback URL; in this case, `https://gitlab.example.com/users/auth`. Include the port number if your GitLab instance uses a non-default port.
-NOTE:
-To prevent an [OAuth2 covert redirect](https://oauth.net/advisories/2014-1-covert-redirect/) vulnerability, append `/users/auth` to the end of the GitHub authorization callback URL.
-
See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
After you have configured the GitHub provider, you need the following information. You must substitute that information in the GitLab configuration file in these next steps.
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 4bd0bddfd7d..e8dadd88147 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Auto DevOps **(FREE)**
-> - Generally available on GitLab 11.0.
+> - Introduced in GitLab 11.0 for general availability.
GitLab Auto DevOps helps to reduce the complexity of software delivery by
setting up pipelines and integrations for you. Instead of requiring you to
@@ -38,7 +38,7 @@ For a developer's guide, read [Auto DevOps development guide](../../development/
## Enabled by default
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41729) in GitLab 11.3.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41729) in GitLab 11.3.
On self-managed instances, Auto DevOps is enabled by default for all projects.
It attempts to run on all pipelines in each project. An instance administrator can
@@ -205,7 +205,7 @@ After enabling the feature, an Auto DevOps pipeline is triggered on the `master`
### At the group level
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/52447) in GitLab 11.10.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/52447) in GitLab 11.10.
Only administrators and group owners can enable or disable Auto DevOps at the group level.
@@ -232,7 +232,7 @@ Auto DevOps at the group and project level, respectively.
### Deployment strategy
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/38542) in GitLab 11.0.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/38542) in GitLab 11.0.
You can change the deployment strategy used by Auto DevOps by visiting your
project's **Settings > CI/CD > Auto DevOps**. The following options
diff --git a/spec/factories/alert_management/alerts.rb b/spec/factories/alert_management/alerts.rb
index e36e4c38013..ee1225b9542 100644
--- a/spec/factories/alert_management/alerts.rb
+++ b/spec/factories/alert_management/alerts.rb
@@ -47,10 +47,6 @@ FactoryBot.define do
hosts { [FFaker::Internet.ip_v4_address] }
end
- trait :with_ended_at do
- ended_at { Time.current }
- end
-
trait :without_ended_at do
ended_at { nil }
end
@@ -67,7 +63,7 @@ FactoryBot.define do
trait :resolved do
status { AlertManagement::Alert.status_value(:resolved) }
- with_ended_at
+ ended_at { Time.current }
end
trait :ignored do
diff --git a/spec/factories/prometheus_alert_event.rb b/spec/factories/prometheus_alert_event.rb
index 281fbacabe2..7771a8d5cb7 100644
--- a/spec/factories/prometheus_alert_event.rb
+++ b/spec/factories/prometheus_alert_event.rb
@@ -13,10 +13,5 @@ FactoryBot.define do
ended_at { Time.now }
payload_key { nil }
end
-
- trait :none do
- status { nil }
- started_at { nil }
- end
end
end
diff --git a/spec/factories/self_managed_prometheus_alert_event.rb b/spec/factories/self_managed_prometheus_alert_event.rb
index 238942e2c46..3a48aba5f54 100644
--- a/spec/factories/self_managed_prometheus_alert_event.rb
+++ b/spec/factories/self_managed_prometheus_alert_event.rb
@@ -8,16 +8,5 @@ FactoryBot.define do
title { 'alert' }
query_expression { 'vector(2)' }
started_at { Time.now }
-
- trait :resolved do
- status { SelfManagedPrometheusAlertEvent.status_value_for(:resolved) }
- ended_at { Time.now }
- payload_key { nil }
- end
-
- trait :none do
- status { nil }
- started_at { nil }
- end
end
end
diff --git a/spec/factories_spec.rb b/spec/factories_spec.rb
index c381fb82ba0..a297b0b72f6 100644
--- a/spec/factories_spec.rb
+++ b/spec/factories_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe 'factories' do
def skipped_traits
[
- [:alert_management_alert, :with_ended_at],
[:audit_event, :unauthenticated],
[:ci_build_trace_chunk, :fog_with_data],
[:ci_job_artifact, :remote_store],
@@ -32,10 +31,7 @@ RSpec.describe 'factories' do
[:pages_domain, :explicit_ecdsa],
[:project_member, :blocked],
[:project, :remote_mirror],
- [:prometheus_alert_event, :none],
[:remote_mirror, :ssh],
- [:self_managed_prometheus_alert_event, :resolved],
- [:self_managed_prometheus_alert_event, :none],
[:user_preference, :only_comments]
]
end
diff --git a/spec/frontend/issues_list/components/issuable_spec.js b/spec/frontend/issues_list/components/issuable_spec.js
index a8bf124373b..236eab6e276 100644
--- a/spec/frontend/issues_list/components/issuable_spec.js
+++ b/spec/frontend/issues_list/components/issuable_spec.js
@@ -1,4 +1,4 @@
-import { GlSprintf, GlLabel, GlIcon } from '@gitlab/ui';
+import { GlSprintf, GlLabel, GlIcon, GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants';
import { trimText } from 'helpers/text_helper';
@@ -31,6 +31,7 @@ const TEST_MILESTONE = {
};
const TEXT_CLOSED = 'CLOSED';
const TEST_META_COUNT = 100;
+const MOCK_GITLAB_URL = 'http://0.0.0.0:3000';
describe('Issuable component', () => {
let issuable;
@@ -54,6 +55,7 @@ describe('Issuable component', () => {
beforeEach(() => {
issuable = { ...simpleIssue };
+ gon.gitlab_url = MOCK_GITLAB_URL;
});
afterEach(() => {
@@ -199,6 +201,33 @@ describe('Issuable component', () => {
it('renders no comments', () => {
expect(findNotes().classes('no-comments')).toBe(true);
});
+
+ it.each`
+ gitlabWebUrl | webUrl | expectedHref | expectedTarget | isExternal
+ ${undefined} | ${`${MOCK_GITLAB_URL}/issue`} | ${`${MOCK_GITLAB_URL}/issue`} | ${undefined} | ${false}
+ ${undefined} | ${'https://jira.com/issue'} | ${'https://jira.com/issue'} | ${'_blank'} | ${true}
+ ${'/gitlab-org/issue'} | ${'https://jira.com/issue'} | ${'/gitlab-org/issue'} | ${undefined} | ${false}
+ `(
+ 'renders issuable title correctly when `gitlabWebUrl` is `$gitlabWebUrl` and webUrl is `$webUrl`',
+ async ({ webUrl, gitlabWebUrl, expectedHref, expectedTarget, isExternal }) => {
+ factory({
+ issuable: {
+ ...issuable,
+ web_url: webUrl,
+ gitlab_web_url: gitlabWebUrl,
+ },
+ });
+
+ const titleEl = findIssuableTitle();
+
+ expect(titleEl.exists()).toBe(true);
+ expect(titleEl.find(GlLink).attributes('href')).toBe(expectedHref);
+ expect(titleEl.find(GlLink).attributes('target')).toBe(expectedTarget);
+ expect(titleEl.find(GlLink).text()).toBe(issuable.title);
+
+ expect(titleEl.find(GlIcon).exists()).toBe(isExternal);
+ },
+ );
});
describe('with confidential issuable', () => {
diff --git a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
index 8ed419a4a61..270c89e674c 100644
--- a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
+++ b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
@@ -62,6 +62,20 @@ describe('RevisionDropdown component', () => {
expect(wrapper.vm.tags).toEqual(Tags);
});
+ it('sets branches and tags to be an empty array when no tags or branches are given', async () => {
+ axiosMock.onGet(defaultProps.refsProjectPath).replyOnce(200, {
+ Branches: undefined,
+ Tags: undefined,
+ });
+
+ createComponent();
+
+ await axios.waitForAll();
+
+ expect(wrapper.vm.branches).toEqual([]);
+ expect(wrapper.vm.tags).toEqual([]);
+ });
+
it('shows flash message on error', async () => {
axiosMock.onGet('some/invalid/path').replyOnce(404);
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index d0282e14d5f..37b43066a62 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -335,6 +335,7 @@ container_repositories:
- project
- name
project:
+- external_approval_rules
- taggings
- base_tags
- tag_taggings
diff --git a/spec/models/prometheus_alert_event_spec.rb b/spec/models/prometheus_alert_event_spec.rb
index 913ca7db0be..6bff549bc4b 100644
--- a/spec/models/prometheus_alert_event_spec.rb
+++ b/spec/models/prometheus_alert_event_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe PrometheusAlertEvent do
let(:started_at) { Time.current }
context 'when status is none' do
- subject { build(:prometheus_alert_event, :none) }
+ subject { build(:prometheus_alert_event, status: nil, started_at: nil) }
it 'fires an event' do
result = subject.fire(started_at)