summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-30 15:11:08 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-30 15:11:08 +0000
commit2cba3ab8e7b2d6b32be6910d15b53860f2c2140e (patch)
tree28bd2516c6030e038bb8ea1143cc6ec11f953fd0
parenta10d237d37e78cbe84f72fffaeff74dc73f1e68f (diff)
downloadgitlab-ce-2cba3ab8e7b2d6b32be6910d15b53860f2c2140e.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/cache-repo.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml40
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml70
-rw-r--r--.gitlab/issue_templates/Experiment Successful Cleanup.md1
-rw-r--r--.gitlab/issue_templates/experiment_tracking_template.md1
-rw-r--r--.rubocop_manual_todo.yml3
-rw-r--r--app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue2
-rw-r--r--app/assets/javascripts/boards/components/board_add_new_column.vue18
-rw-r--r--app/assets/javascripts/diffs/store/getters.js12
-rw-r--r--app/assets/javascripts/notes/components/note_attachment.vue2
-rw-r--r--app/assets/stylesheets/pages/login.scss3
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss4
-rw-r--r--app/assets/stylesheets/pages/note_form.scss1
-rw-r--r--app/assets/stylesheets/pages/notifications.scss4
-rw-r--r--app/finders/group_members_finder.rb54
-rw-r--r--app/models/deployment.rb2
-rw-r--r--app/models/environment.rb6
-rw-r--r--app/models/member.rb6
-rw-r--r--app/views/events/event/_note.html.haml2
-rw-r--r--app/views/projects/merge_requests/conflicts/show.html.haml2
-rw-r--r--app/views/projects/merge_requests/creations/_new_compare.html.haml2
-rw-r--r--app/views/projects/merge_requests/creations/_new_submit.html.haml2
-rw-r--r--app/views/projects/merge_requests/creations/new.html.haml4
-rw-r--r--app/views/projects/merge_requests/edit.html.haml4
-rw-r--r--app/views/projects/merge_requests/index.html.haml2
-rw-r--r--app/views/projects/merge_requests/invalid.html.haml4
-rw-r--r--app/views/projects/merge_requests/show.html.haml4
-rw-r--r--app/views/shared/notes/_note.html.haml2
-rw-r--r--changelogs/unreleased/273034-support-semver-on-generic-packages.yml5
-rw-r--r--changelogs/unreleased/fix-group_members_max_access_level.yml5
-rw-r--r--changelogs/unreleased/fix-obsolte-production-identifier.yml5
-rw-r--r--changelogs/unreleased/issue-220040-fix-rails-savebang-admin-controllers.yml5
-rw-r--r--changelogs/unreleased/tor-defect-overview-placeholder-message-diffs-new-data-source.yml6
-rw-r--r--config/feature_flags/development/ci_needs_optional.yml2
-rw-r--r--config/feature_flags/development/usage_data_o_pipeline_authoring_unique_users_pushing_mr_ciconfigfile.yml2
-rw-r--r--doc/api/members.md4
-rw-r--r--doc/ci/yaml/README.md15
-rw-r--r--doc/user/analytics/value_stream_analytics.md10
-rw-r--r--doc/user/packages/generic_packages/index.md2
-rw-r--r--lib/gitlab/regex.rb2
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/controllers/admin/impersonations_controller_spec.rb2
-rw-r--r--spec/controllers/admin/runners_controller_spec.rb4
-rw-r--r--spec/controllers/admin/services_controller_spec.rb2
-rw-r--r--spec/features/merge_request/user_creates_merge_request_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_breadcrumb_links_spec.rb2
-rw-r--r--spec/features/projects/files/user_creates_directory_spec.rb2
-rw-r--r--spec/finders/group_members_finder_spec.rb282
-rw-r--r--spec/frontend/boards/components/board_add_new_column_spec.js10
-rw-r--r--spec/frontend/diffs/store/getters_spec.js44
-rw-r--r--spec/frontend/error_tracking/components/error_tracking_list_spec.js1
-rw-r--r--spec/frontend/notes/components/note_body_spec.js17
-rw-r--r--spec/lib/gitlab/regex_spec.rb9
-rw-r--r--spec/models/deployment_spec.rb26
-rw-r--r--spec/models/environment_spec.rb33
-rw-r--r--spec/models/member_spec.rb18
-rw-r--r--spec/models/packages/package_spec.rb9
-rw-r--r--spec/requests/api/generic_packages_spec.rb33
60 files changed, 471 insertions, 354 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 38115beec69..7e4f1a02646 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -38,7 +38,7 @@ workflow:
when: never
# For merge requests, create a pipeline.
- if: '$CI_MERGE_REQUEST_IID'
- # For `master` branch, create a pipeline (this includes on schedules, pushes, merges, etc.).
+ # For `$CI_DEFAULT_BRANCH` branch, create a pipeline (this includes on schedules, pushes, merges, etc.).
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
# For tags, create a pipeline.
- if: '$CI_COMMIT_TAG'
diff --git a/.gitlab/ci/cache-repo.gitlab-ci.yml b/.gitlab/ci/cache-repo.gitlab-ci.yml
index 48724f7e65c..475cbca3156 100644
--- a/.gitlab/ci/cache-repo.gitlab-ci.yml
+++ b/.gitlab/ci/cache-repo.gitlab-ci.yml
@@ -1,4 +1,4 @@
-# Builds a cached .tar.gz of the master branch with full history and
+# Builds a cached .tar.gz of the $CI_DEFAULT_BRANCH branch with full history and
# uploads it to Google Cloud Storage. This archive is downloaded by a
# script defined by a CI/CD variable named CI_PRE_CLONE_SCRIPT. This has
# two benefits:
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index 910a58bcd0e..e739b046ff7 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -246,7 +246,7 @@ coverage-frontend:
extends:
- .default-retry
- .yarn-cache
- - .frontend:rules:ee-mr-and-master-only
+ - .frontend:rules:ee-mr-and-default-branch-only
needs: ["jest"]
stage: post-test
before_script:
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index f4ea6e3ae01..6b5c617dccc 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -142,7 +142,7 @@
############################
#######################################################
-# EE/FOSS: default refs (MRs, master, schedules) jobs #
+# EE/FOSS: default refs (MRs, default branch, schedules) jobs #
setup-test-env:
extends:
- .rails-job-base
@@ -347,7 +347,7 @@ db:migrate:reset:
db:check-schema:
extends:
- .db-job-base
- - .rails:rules:ee-mr-and-master-only
+ - .rails:rules:ee-mr-and-default-branch-only
script:
- source scripts/schema_changed.sh
@@ -538,11 +538,11 @@ rspec:feature-flags:
run_timed_command "bundle exec scripts/used-feature-flags";
fi
-# EE/FOSS: default refs (MRs, master, schedules) jobs #
+# EE/FOSS: default refs (MRs, default branch, schedules) jobs #
#######################################################
##################################################
-# EE: default refs (MRs, master, schedules) jobs #
+# EE: default refs (MRs, default branch, schedules) jobs #
rspec migration pg11-as-if-foss:
extends:
- .rspec-base-pg11-as-if-foss
@@ -685,81 +685,81 @@ db:rollback geo:
script:
- bundle exec rake geo:db:migrate VERSION=20170627195211
- bundle exec rake geo:db:migrate
-# EE: default refs (MRs, master, schedules) jobs #
+# EE: default refs (MRs, default branch, schedules) jobs #
##################################################
##########################################
-# EE/FOSS: master nightly scheduled jobs #
+# EE/FOSS: default branch nightly scheduled jobs #
rspec migration pg12:
extends:
- .rspec-base-pg12
- .rspec-base-migration
- - .rails:rules:master-schedule-nightly--code-backstage
+ - .rails:rules:default-branch-schedule-nightly--code-backstage
- .rspec-migration-parallel
rspec unit pg12:
extends:
- .rspec-base-pg12
- - .rails:rules:master-schedule-nightly--code-backstage
+ - .rails:rules:default-branch-schedule-nightly--code-backstage
- .rspec-unit-parallel
rspec integration pg12:
extends:
- .rspec-base-pg12
- - .rails:rules:master-schedule-nightly--code-backstage
+ - .rails:rules:default-branch-schedule-nightly--code-backstage
- .rspec-integration-parallel
rspec system pg12:
extends:
- .rspec-base-pg12
- - .rails:rules:master-schedule-nightly--code-backstage
+ - .rails:rules:default-branch-schedule-nightly--code-backstage
- .rspec-system-parallel
-# EE/FOSS: master nightly scheduled jobs #
+# EE/FOSS: default branch nightly scheduled jobs #
##########################################
#####################################
-# EE: master nightly scheduled jobs #
+# EE: default branch nightly scheduled jobs #
rspec-ee migration pg12:
extends:
- .rspec-ee-base-pg12
- .rspec-base-migration
- - .rails:rules:master-schedule-nightly--code-backstage-ee-only
+ - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-migration-parallel
rspec-ee unit pg12:
extends:
- .rspec-ee-base-pg12
- - .rails:rules:master-schedule-nightly--code-backstage-ee-only
+ - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-unit-parallel
rspec-ee integration pg12:
extends:
- .rspec-ee-base-pg12
- - .rails:rules:master-schedule-nightly--code-backstage-ee-only
+ - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-integration-parallel
rspec-ee system pg12:
extends:
- .rspec-ee-base-pg12
- - .rails:rules:master-schedule-nightly--code-backstage-ee-only
+ - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-system-parallel
rspec-ee unit pg12 geo:
extends:
- .rspec-ee-base-geo-pg12
- - .rails:rules:master-schedule-nightly--code-backstage-ee-only
+ - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-unit-geo-parallel
rspec-ee integration pg12 geo:
extends:
- .rspec-ee-base-geo-pg12
- - .rails:rules:master-schedule-nightly--code-backstage-ee-only
+ - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
rspec-ee system pg12 geo:
extends:
- .rspec-ee-base-geo-pg12
- - .rails:rules:master-schedule-nightly--code-backstage-ee-only
-# EE: master nightly scheduled jobs #
+ - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
+# EE: default branch nightly scheduled jobs #
#####################################
##################################################
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 5464409254a..39522f7b60c 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -11,25 +11,25 @@
if: '$CI_PROJECT_NAME != "gitlab-foss" && $CI_PROJECT_NAME != "gitlab-ce" && $CI_PROJECT_NAME != "gitlabhq"'
.if-default-refs: &if-default-refs
- if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
+ if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
-.if-master-refs: &if-master-refs
- if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME == "main"'
+.if-default-branch-refs: &if-default-branch-refs
+ if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
-.if-master-push: &if-master-push
- if: '($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_REF_NAME == "main") && $CI_PIPELINE_SOURCE == "push"'
+.if-default-branch-push: &if-default-branch-push
+ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"'
-.if-master-schedule-2-hourly: &if-master-schedule-2-hourly
- if: '($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_REF_NAME == "main") && $CI_PIPELINE_SOURCE == "schedule" && $FREQUENCY == "2-hourly"'
+.if-default-branch-schedule-2-hourly: &if-default-branch-schedule-2-hourly
+ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "schedule" && $FREQUENCY == "2-hourly"'
-.if-master-schedule-nightly: &if-master-schedule-nightly
- if: '($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_REF_NAME == "main") && $CI_PIPELINE_SOURCE == "schedule" && $FREQUENCY == "nightly"'
+.if-default-branch-schedule-nightly: &if-default-branch-schedule-nightly
+ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "schedule" && $FREQUENCY == "nightly"'
.if-auto-deploy-branches: &if-auto-deploy-branches
if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/'
-.if-master-or-tag: &if-master-or-tag
- if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_TAG'
+.if-default-branch-or-tag: &if-default-branch-or-tag
+ if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_TAG'
.if-merge-request: &if-merge-request
if: '$CI_MERGE_REQUEST_IID'
@@ -52,8 +52,8 @@
.if-dot-com-gitlab-org-schedule: &if-dot-com-gitlab-org-schedule
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_PIPELINE_SOURCE == "schedule"'
-.if-dot-com-gitlab-org-master: &if-dot-com-gitlab-org-master
- if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && ($CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME == "main")'
+.if-dot-com-gitlab-org-default-branch: &if-dot-com-gitlab-org-default-branch
+ if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
.if-dot-com-gitlab-org-merge-request: &if-dot-com-gitlab-org-merge-request
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_MERGE_REQUEST_IID'
@@ -293,7 +293,7 @@
################
.shared:rules:update-cache:
rules:
- - <<: *if-master-schedule-2-hourly
+ - <<: *if-default-branch-schedule-2-hourly
- <<: *if-security-schedule
- <<: *if-merge-request-title-update-caches
@@ -435,26 +435,26 @@
- <<: *if-merge-request
changes: *frontend-patterns
-.frontend:rules:ee-mr-and-master-only:
+.frontend:rules:ee-mr-and-default-branch-only:
rules:
- <<: *if-not-ee
when: never
- <<: *if-merge-request
changes: *code-backstage-patterns
when: always
- - <<: *if-master-refs
+ - <<: *if-default-branch-refs
changes: *code-backstage-patterns
.frontend:rules:qa-frontend-node:
rules:
- - <<: *if-master-refs
+ - <<: *if-default-branch-refs
changes: *frontend-dependency-patterns
- <<: *if-merge-request
changes: *frontend-dependency-patterns
.frontend:rules:qa-frontend-node-latest:
rules:
- - <<: *if-master-refs
+ - <<: *if-default-branch-refs
changes: *frontend-dependency-patterns
allow_failure: true
- <<: *if-merge-request
@@ -465,7 +465,7 @@
rules:
- <<: *if-not-canonical-namespace
when: never
- - if: '$DANGER_GITLAB_API_TOKEN && $CI_MERGE_REQUEST_IID && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main")'
+ - if: '$DANGER_GITLAB_API_TOKEN && $CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
changes: *frontend-patterns
allow_failure: true
@@ -485,7 +485,7 @@
rules:
- <<: *if-not-ee
when: never
- - <<: *if-master-schedule-2-hourly
+ - <<: *if-default-branch-schedule-2-hourly
############
# QA rules #
@@ -825,14 +825,14 @@
- changes: *db-library-patterns
- <<: *if-merge-request-title-run-all-rspec
-.rails:rules:ee-mr-and-master-only:
+.rails:rules:ee-mr-and-default-branch-only:
rules:
- <<: *if-not-ee
when: never
- <<: *if-merge-request-title-run-all-rspec
- <<: *if-merge-request
changes: *code-backstage-patterns
- - <<: *if-master-refs
+ - <<: *if-default-branch-refs
changes: *code-backstage-patterns
.rails:rules:detect-tests:
@@ -888,7 +888,7 @@
rules:
- <<: *if-not-ee
when: never
- - <<: *if-master-schedule-nightly
+ - <<: *if-default-branch-schedule-nightly
- <<: *if-merge-request-title-run-all-rspec
.rails:rules:rspec-coverage:
@@ -898,7 +898,7 @@
- <<: *if-merge-request
changes: *code-backstage-patterns
when: always
- - <<: *if-master-schedule-2-hourly
+ - <<: *if-default-branch-schedule-2-hourly
- <<: *if-merge-request-title-run-all-rspec
when: always
@@ -906,21 +906,21 @@
rules:
- <<: *if-not-ee
when: never
- - <<: *if-master-schedule-2-hourly
+ - <<: *if-default-branch-schedule-2-hourly
allow_failure: true
- <<: *if-merge-request-title-run-all-rspec
-.rails:rules:master-schedule-nightly--code-backstage:
+.rails:rules:default-branch-schedule-nightly--code-backstage:
rules:
- - <<: *if-master-schedule-nightly
+ - <<: *if-default-branch-schedule-nightly
- <<: *if-merge-request
changes: [".gitlab/ci/rails.gitlab-ci.yml"]
-.rails:rules:master-schedule-nightly--code-backstage-ee-only:
+.rails:rules:default-branch-schedule-nightly--code-backstage-ee-only:
rules:
- <<: *if-not-ee
when: never
- - <<: *if-master-schedule-nightly
+ - <<: *if-default-branch-schedule-nightly
- <<: *if-merge-request
changes: [".gitlab/ci/rails.gitlab-ci.yml"]
@@ -946,7 +946,7 @@
rules:
- if: '$CODE_QUALITY_DISABLED'
when: never
- # - <<: *if-master-refs # To be done in a later iteration: https://gitlab.com/gitlab-org/gitlab/issues/31160#note_278188255
+ # - <<: *if-default-branch-refs # To be done in a later iteration: https://gitlab.com/gitlab-org/gitlab/issues/31160#note_278188255
- <<: *if-default-refs
changes: *code-backstage-patterns
allow_failure: true
@@ -955,7 +955,7 @@
rules:
- if: '$SAST_DISABLED || $GITLAB_FEATURES !~ /\bsast\b/'
when: never
- # - <<: *if-master-refs # To be done in a later iteration: https://gitlab.com/gitlab-org/gitlab/issues/31160#note_278188255
+ # - <<: *if-default-branch-refs # To be done in a later iteration: https://gitlab.com/gitlab-org/gitlab/issues/31160#note_278188255
- <<: *if-default-refs
changes: *code-backstage-qa-patterns
allow_failure: true
@@ -964,7 +964,7 @@
rules:
- if: '$DEPENDENCY_SCANNING_DISABLED || $GITLAB_FEATURES !~ /\bdependency_scanning\b/'
when: never
- # - <<: *if-master-refs # To be done in a later iteration: https://gitlab.com/gitlab-org/gitlab/issues/31160#note_278188255
+ # - <<: *if-default-branch-refs # To be done in a later iteration: https://gitlab.com/gitlab-org/gitlab/issues/31160#note_278188255
- <<: *if-default-refs
changes: *code-backstage-qa-patterns
allow_failure: true
@@ -985,7 +985,7 @@
rules:
- if: '$DAST_DISABLED || $GITLAB_FEATURES !~ /\bdast\b/'
when: never
- - <<: *if-master-schedule-nightly
+ - <<: *if-default-branch-schedule-nightly
allow_failure: true
.reports:rules:license_scanning:
@@ -1119,13 +1119,13 @@
rules:
- <<: *if-not-canonical-namespace
when: never
- - <<: *if-master-or-tag
+ - <<: *if-default-branch-or-tag
changes: *code-backstage-qa-patterns
when: on_success
.setup:rules:dont-interrupt-me:
rules:
- - <<: *if-master-or-tag
+ - <<: *if-default-branch-or-tag
allow_failure: true
- <<: *if-auto-deploy-branches
allow_failure: true
diff --git a/.gitlab/issue_templates/Experiment Successful Cleanup.md b/.gitlab/issue_templates/Experiment Successful Cleanup.md
index afe4793cdfc..42f26342342 100644
--- a/.gitlab/issue_templates/Experiment Successful Cleanup.md
+++ b/.gitlab/issue_templates/Experiment Successful Cleanup.md
@@ -15,5 +15,6 @@ The changes need to become an official part of the product.
- [ ] Optional: Migrate experiment to a default enabled [feature flag](https://docs.gitlab.com/ee/development/feature_flags) for one milestone and add a changelog. Converting to a feature flag can be skipped at the ICs discretion if risk is deemed low with consideration to both SaaS and (if applicable) self managed
- [ ] In the next milestone, [remove the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) if applicable
- [ ] After the flag removal is deployed, [clean up the feature/experiment feature flags](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
+- [ ] Ensure the corresponding [Experiment Tracking](https://gitlab.com/groups/gitlab-org/-/boards/1352542?label_name[]=devops%3A%3Agrowth&label_name[]=growth%20experiment&label_name[]=experiment%20tracking) issue is updated
/label ~"feature" ~"feature::maintenance" ~"workflow::scheduling" ~"growth experiment" ~"feature flag"
diff --git a/.gitlab/issue_templates/experiment_tracking_template.md b/.gitlab/issue_templates/experiment_tracking_template.md
index 432ae57e594..6d05932b3d6 100644
--- a/.gitlab/issue_templates/experiment_tracking_template.md
+++ b/.gitlab/issue_templates/experiment_tracking_template.md
@@ -81,6 +81,7 @@ If applicable, any groups/projects that are happy to have this feature turned on
- [ ] Announce on the issue that the flag has been enabled
- [ ] Remove experiment code and feature flag and add changelog entry - a separate [cleanup issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Experiment%20Successful%20Cleanup) might be required
- [ ] After the flag removal is deployed, [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
+- [ ] Assign to the product manager to update the [knowledge base](https://about.gitlab.com/direction/growth/#growth-insights-knowledge-base) (if applicable)
## Rollback Steps
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index d4875d7e89c..ff042f763a0 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -177,9 +177,6 @@ Rails/SaveBang:
- 'qa/qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_http_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/3_create/repository/pull_mirroring_over_ssh_with_key_spec.rb'
- 'spec/controllers/abuse_reports_controller_spec.rb'
- - 'spec/controllers/admin/impersonations_controller_spec.rb'
- - 'spec/controllers/admin/runners_controller_spec.rb'
- - 'spec/controllers/admin/services_controller_spec.rb'
- 'spec/controllers/boards/issues_controller_spec.rb'
- 'spec/controllers/groups/milestones_controller_spec.rb'
- 'spec/controllers/groups/runners_controller_spec.rb'
diff --git a/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue b/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
index 6fee40fb061..33e92bfab44 100644
--- a/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
+++ b/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
@@ -108,7 +108,7 @@ export default {
show
:target="target"
placement="right"
- trigger="manual"
+ triggers="manual"
container="viewport"
:css-classes="['suggest-gitlab-ci-yml', 'ml-4']"
>
diff --git a/app/assets/javascripts/boards/components/board_add_new_column.vue b/app/assets/javascripts/boards/components/board_add_new_column.vue
index a77696b70cc..d4b559add6e 100644
--- a/app/assets/javascripts/boards/components/board_add_new_column.vue
+++ b/app/assets/javascripts/boards/components/board_add_new_column.vue
@@ -5,7 +5,6 @@ import BoardAddNewColumnForm from '~/boards/components/board_add_new_column_form
import { ListType } from '~/boards/constants';
import boardsStore from '~/boards/stores/boards_store';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { isScopedLabel } from '~/lib/utils/common_utils';
export default {
components: {
@@ -20,17 +19,12 @@ export default {
data() {
return {
selectedId: null,
+ selectedLabel: null,
};
},
computed: {
...mapState(['labels', 'labelsLoading']),
...mapGetters(['getListByLabelId', 'shouldUseGraphQL']),
- selectedLabel() {
- if (!this.selectedId) {
- return null;
- }
- return this.labels.find(({ id }) => id === this.selectedId);
- },
columnForSelected() {
return this.getListByLabelId(this.selectedId);
},
@@ -83,8 +77,13 @@ export default {
this.fetchLabels(searchTerm);
},
- showScopedLabels(label) {
- return this.scopedLabelsAvailable && isScopedLabel(label);
+ setSelectedItem(selectedId) {
+ const label = this.labels.find(({ id }) => id === selectedId);
+ if (!selectedId || !label) {
+ this.selectedLabel = null;
+ } else {
+ this.selectedLabel = { ...label };
+ }
},
},
};
@@ -116,6 +115,7 @@ export default {
v-if="labels.length > 0"
v-model="selectedId"
class="gl-overflow-y-auto gl-px-5 gl-pt-3"
+ @change="setSelectedItem"
>
<label
v-for="label in labels"
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index 1fc2a684e95..dec3f87b03e 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -156,16 +156,16 @@ export const diffLines = (state) => (file, unifiedDiffComponents) => {
);
};
-export function suggestionCommitMessage(state) {
+export function suggestionCommitMessage(state, _, rootState) {
return (values = {}) =>
computeSuggestionCommitMessage({
message: state.defaultSuggestionCommitMessage,
values: {
- branch_name: state.branchName,
- project_path: state.projectPath,
- project_name: state.projectName,
- username: state.username,
- user_full_name: state.userFullName,
+ branch_name: rootState.page.mrMetadata.branch_name,
+ project_path: rootState.page.mrMetadata.project_path,
+ project_name: rootState.page.mrMetadata.project_name,
+ username: rootState.page.mrMetadata.username,
+ user_full_name: rootState.page.mrMetadata.user_full_name,
...values,
},
});
diff --git a/app/assets/javascripts/notes/components/note_attachment.vue b/app/assets/javascripts/notes/components/note_attachment.vue
index b20facc4032..c49f3e2de99 100644
--- a/app/assets/javascripts/notes/components/note_attachment.vue
+++ b/app/assets/javascripts/notes/components/note_attachment.vue
@@ -24,7 +24,7 @@ export default {
target="_blank"
rel="noopener noreferrer"
>
- <img :src="attachment.url" class="note-image-attach" />
+ <img :src="attachment.url" class="note-image-attach col-lg-4" />
</a>
<div class="attachment">
<a
diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss
index 2d04354a99d..9d437531e6d 100644
--- a/app/assets/stylesheets/pages/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -179,8 +179,9 @@
}
input[type='submit'] {
- @extend .btn-block;
margin-bottom: 0;
+ display: block;
+ width: 100%;
}
.devise-errors {
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 23e368a2e73..36d39c1a613 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -236,8 +236,8 @@ $tabs-holder-z-index: 250;
}
.label-branch {
- @extend .ref-name;
-
+ @include gl-font-monospace;
+ font-size: 95%;
color: $gl-text-color;
font-weight: normal;
overflow: hidden;
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index cb5050fc578..59768f4cda8 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -48,7 +48,6 @@
}
.note-image-attach {
- @extend .col-lg-4;
margin-left: 45px;
float: none;
}
diff --git a/app/assets/stylesheets/pages/notifications.scss b/app/assets/stylesheets/pages/notifications.scss
index 33ab42b5511..298de33888d 100644
--- a/app/assets/stylesheets/pages/notifications.scss
+++ b/app/assets/stylesheets/pages/notifications.scss
@@ -1,8 +1,4 @@
.notification-list-item {
- .dropdown-menu {
- @extend .dropdown-menu-right;
- }
-
@include media-breakpoint-down(sm) {
.notification-dropdown {
width: 100%;
diff --git a/app/finders/group_members_finder.rb b/app/finders/group_members_finder.rb
index 2417b1e0771..a6ecd835527 100644
--- a/app/finders/group_members_finder.rb
+++ b/app/finders/group_members_finder.rb
@@ -21,28 +21,13 @@ class GroupMembersFinder < UnionFinder
end
def execute(include_relations: DEFAULT_RELATIONS)
- group_members = group_members_list
- relations = []
+ return filter_members(group_members_list) if include_relations == [:direct]
- return filter_members(group_members) if include_relations == [:direct]
+ groups = groups_by_relations(include_relations)
+ return GroupMember.none unless groups
- relations << group_members if include_relations.include?(:direct)
+ members = all_group_members(groups).distinct_on_user_with_max_access_level
- if include_relations.include?(:inherited) && group.parent
- parents_members = relation_group_members(group.ancestors)
-
- relations << parents_members
- end
-
- if include_relations.include?(:descendants)
- descendant_members = relation_group_members(group.descendants)
-
- relations << descendant_members
- end
-
- return GroupMember.none if relations.empty?
-
- members = find_union(relations, GroupMember)
filter_members(members)
end
@@ -50,6 +35,25 @@ class GroupMembersFinder < UnionFinder
attr_reader :user, :group
+ def groups_by_relations(include_relations)
+ case include_relations.sort
+ when [:inherited]
+ group.ancestors
+ when [:descendants]
+ group.descendants
+ when [:direct, :inherited]
+ group.self_and_ancestors
+ when [:descendants, :direct]
+ group.self_and_descendants
+ when [:descendants, :inherited]
+ find_union([group.ancestors, group.descendants], Group)
+ when [:descendants, :direct, :inherited]
+ group.self_and_hierarchy
+ else
+ nil
+ end
+ end
+
def filter_members(members)
members = members.search(params[:search]) if params[:search].present?
members = members.sort_by_attribute(params[:sort]) if params[:sort].present?
@@ -69,17 +73,13 @@ class GroupMembersFinder < UnionFinder
group.members
end
- def relation_group_members(relation)
- all_group_members(relation).non_minimal_access
+ def all_group_members(groups)
+ members_of_groups(groups).non_minimal_access
end
- # rubocop: disable CodeReuse/ActiveRecord
- def all_group_members(relation)
- GroupMember.non_request
- .where(source_id: relation.select(:id))
- .where.not(user_id: group.users.select(:id))
+ def members_of_groups(groups)
+ GroupMember.non_request.of_groups(groups)
end
- # rubocop: enable CodeReuse/ActiveRecord
end
GroupMembersFinder.prepend_if_ee('EE::GroupMembersFinder')
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index 423914139ba..446e6174df2 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -226,7 +226,7 @@ class Deployment < ApplicationRecord
end
def update_merge_request_metrics!
- return unless environment.update_merge_request_metrics? && success?
+ return unless environment.production? && success?
merge_requests = project.merge_requests
.joins(:metrics)
diff --git a/app/models/environment.rb b/app/models/environment.rb
index d89909a71a2..96b44c9ac0a 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -11,8 +11,6 @@ class Environment < ApplicationRecord
self.reactive_cache_hard_limit = 10.megabytes
self.reactive_cache_work_type = :external_dependency
- PRODUCTION_ENVIRONMENT_IDENTIFIERS = %w[prod production].freeze
-
belongs_to :project, required: true
use_fast_destroy :all_deployments
@@ -251,10 +249,6 @@ class Environment < ApplicationRecord
last_deployment.try(:created_at)
end
- def update_merge_request_metrics?
- PRODUCTION_ENVIRONMENT_IDENTIFIERS.include?(folder_name.downcase)
- end
-
def ref_path
"refs/#{Repository::REF_ENVIRONMENTS}/#{slug}"
end
diff --git a/app/models/member.rb b/app/models/member.rb
index 38574d67cb6..3f6845cc454 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -137,6 +137,12 @@ class Member < ApplicationRecord
scope :with_source_id, ->(source_id) { where(source_id: source_id) }
scope :including_source, -> { includes(:source) }
+ scope :distinct_on_user_with_max_access_level, -> do
+ distinct_members = select('DISTINCT ON (user_id, invite_email) *')
+ .order('user_id, invite_email, access_level DESC, expires_at DESC, created_at ASC')
+ Member.from(distinct_members, :members)
+ end
+
scope :order_name_asc, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.name', 'ASC')) }
scope :order_name_desc, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.name', 'DESC')) }
scope :order_recent_sign_in, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.last_sign_in_at', 'DESC')) }
diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml
index 2fa595503e5..d08c3d5ba41 100644
--- a/app/views/events/event/_note.html.haml
+++ b/app/views/events/event/_note.html.haml
@@ -22,7 +22,7 @@
- if note.attachment.url
- if note.attachment.image?
= link_to note.attachment.url, target: '_blank' do
- = image_tag note.attachment.url, class: 'note-image-attach'
+ = image_tag note.attachment.url, class: 'note-image-attach col-lg-4'
- else
= link_to note.attachment.url, target: '_blank', class: 'note-file-attach' do
= sprite_icon("paperclip")
diff --git a/app/views/projects/merge_requests/conflicts/show.html.haml b/app/views/projects/merge_requests/conflicts/show.html.haml
index e02f126d165..ee296258d04 100644
--- a/app/views/projects/merge_requests/conflicts/show.html.haml
+++ b/app/views/projects/merge_requests/conflicts/show.html.haml
@@ -1,4 +1,4 @@
-- page_title _("Merge Conflicts"), "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge Requests")
+- page_title _("Merge Conflicts"), "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge requests")
- add_page_specific_style 'page_bundles/merge_conflicts'
= render "projects/merge_requests/mr_title"
diff --git a/app/views/projects/merge_requests/creations/_new_compare.html.haml b/app/views/projects/merge_requests/creations/_new_compare.html.haml
index c7861f4a01a..7082bf4b8b0 100644
--- a/app/views/projects/merge_requests/creations/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_compare.html.haml
@@ -1,5 +1,5 @@
%h3.page-title
- New Merge Request
+ New merge request
= form_for [@project, @merge_request], url: project_new_merge_request_path(@project), method: :get, html: { class: "merge-request-form js-requires-input" } do |f|
- if params[:nav_source].present?
diff --git a/app/views/projects/merge_requests/creations/_new_submit.html.haml b/app/views/projects/merge_requests/creations/_new_submit.html.haml
index 3631ddd5c3e..a8facf1c6fd 100644
--- a/app/views/projects/merge_requests/creations/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_submit.html.haml
@@ -1,5 +1,5 @@
%h3.page-title
- New Merge Request
+ New merge request
= form_for [@project, @merge_request], html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f|
= render 'shared/issuable/form', f: f, issuable: @merge_request, commits: @commits, presenter: @mr_presenter
= f.hidden_field :source_project_id
diff --git a/app/views/projects/merge_requests/creations/new.html.haml b/app/views/projects/merge_requests/creations/new.html.haml
index 0741b24a5a1..6a8894384df 100644
--- a/app/views/projects/merge_requests/creations/new.html.haml
+++ b/app/views/projects/merge_requests/creations/new.html.haml
@@ -1,6 +1,6 @@
-- add_to_breadcrumbs _("Merge Requests"), project_merge_requests_path(@project)
+- add_to_breadcrumbs _("Merge requests"), project_merge_requests_path(@project)
- breadcrumb_title _("New")
-- page_title _("New Merge Request")
+- page_title _("New merge request")
- add_page_specific_style 'page_bundles/pipelines'
- add_page_specific_style 'page_bundles/ci_status'
diff --git a/app/views/projects/merge_requests/edit.html.haml b/app/views/projects/merge_requests/edit.html.haml
index a4bb790ce0b..019015a4d86 100644
--- a/app/views/projects/merge_requests/edit.html.haml
+++ b/app/views/projects/merge_requests/edit.html.haml
@@ -1,5 +1,5 @@
-- page_title _("Edit"), "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge Requests")
+- page_title _("Edit"), "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge requests")
%h3.page-title
- Edit Merge Request #{@merge_request.to_reference}
+ Edit merge request #{@merge_request.to_reference}
= render 'form'
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index 62a251c7015..22d78418c5b 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -3,7 +3,7 @@
- new_merge_request_path = project_new_merge_request_path(merge_project) if merge_project
- issuable_type = 'merge_request'
-- page_title _("Merge Requests")
+- page_title _("Merge requests")
- new_merge_request_email = @project.new_issuable_address(current_user, 'merge_request')
= render 'projects/last_push'
diff --git a/app/views/projects/merge_requests/invalid.html.haml b/app/views/projects/merge_requests/invalid.html.haml
index df942c11883..f0bf5af7732 100644
--- a/app/views/projects/merge_requests/invalid.html.haml
+++ b/app/views/projects/merge_requests/invalid.html.haml
@@ -1,4 +1,4 @@
-- page_title "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge Requests")
+- page_title "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge requests")
- badge_css_classes = "badge gl-text-white"
- badge_info_css_classes = "#{badge_css_classes} badge-info"
- badge_inverse_css_classes = "#{badge_css_classes} badge-inverse"
@@ -25,4 +25,4 @@
of internal error
%strong
- Please close Merge Request or change branches with existing one
+ Please close merge request or change branches with existing one
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index 36491b0d8b8..24594b732a4 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -1,8 +1,8 @@
- @gfm_form = true
- @content_class = "merge-request-container#{' limit-container-width' unless fluid_layout}"
-- add_to_breadcrumbs _("Merge Requests"), project_merge_requests_path(@project)
+- add_to_breadcrumbs _("Merge requests"), project_merge_requests_path(@project)
- breadcrumb_title @merge_request.to_reference
-- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", _("Merge Requests")
+- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", _("Merge requests")
- page_description @merge_request.description_html
- page_card_attributes @merge_request.card_attributes
- suggest_changes_help_path = help_page_path('user/discussions/index.md', anchor: 'suggest-changes')
diff --git a/app/views/shared/notes/_note.html.haml b/app/views/shared/notes/_note.html.haml
index f1352be28e3..6549c86ab29 100644
--- a/app/views/shared/notes/_note.html.haml
+++ b/app/views/shared/notes/_note.html.haml
@@ -69,7 +69,7 @@
.note-attachment
- if note.attachment.image?
= link_to note.attachment.url, target: '_blank' do
- = image_tag note.attachment.url, class: 'note-image-attach'
+ = image_tag note.attachment.url, class: 'note-image-attach col-lg-4'
.attachment
= link_to note.attachment.url, target: '_blank' do
= sprite_icon('paperclip')
diff --git a/changelogs/unreleased/273034-support-semver-on-generic-packages.yml b/changelogs/unreleased/273034-support-semver-on-generic-packages.yml
new file mode 100644
index 00000000000..14fabea7c1b
--- /dev/null
+++ b/changelogs/unreleased/273034-support-semver-on-generic-packages.yml
@@ -0,0 +1,5 @@
+---
+title: Relax version validation on generic packages
+merge_request: 56755
+author:
+type: changed
diff --git a/changelogs/unreleased/fix-group_members_max_access_level.yml b/changelogs/unreleased/fix-group_members_max_access_level.yml
new file mode 100644
index 00000000000..ee7408c3a51
--- /dev/null
+++ b/changelogs/unreleased/fix-group_members_max_access_level.yml
@@ -0,0 +1,5 @@
+---
+title: Fix derivation of effective permissions (access level) of group members
+merge_request: 56677
+author: Jonas Wälter @wwwjon
+type: fixed
diff --git a/changelogs/unreleased/fix-obsolte-production-identifier.yml b/changelogs/unreleased/fix-obsolte-production-identifier.yml
new file mode 100644
index 00000000000..13ec9ff2876
--- /dev/null
+++ b/changelogs/unreleased/fix-obsolte-production-identifier.yml
@@ -0,0 +1,5 @@
+---
+title: Fix inconsistent production environment definition on VSA
+merge_request: 57557
+author:
+type: fixed
diff --git a/changelogs/unreleased/issue-220040-fix-rails-savebang-admin-controllers.yml b/changelogs/unreleased/issue-220040-fix-rails-savebang-admin-controllers.yml
new file mode 100644
index 00000000000..ff9b464c403
--- /dev/null
+++ b/changelogs/unreleased/issue-220040-fix-rails-savebang-admin-controllers.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Rails/SaveBang Rubocop offenses for admin controllers
+merge_request: 57644
+author: Huzaifa Iftikhar @huzaifaiftikhar
+type: fixed
diff --git a/changelogs/unreleased/tor-defect-overview-placeholder-message-diffs-new-data-source.yml b/changelogs/unreleased/tor-defect-overview-placeholder-message-diffs-new-data-source.yml
new file mode 100644
index 00000000000..d602bad9d4e
--- /dev/null
+++ b/changelogs/unreleased/tor-defect-overview-placeholder-message-diffs-new-data-source.yml
@@ -0,0 +1,6 @@
+---
+title: Hydrate some of the variables in the Overview tab suggestion commit placeholder
+ by switching the Diffs data source for it
+merge_request: 57419
+author:
+type: changed
diff --git a/config/feature_flags/development/ci_needs_optional.yml b/config/feature_flags/development/ci_needs_optional.yml
index fcbe9bf6106..eacb0ab6d51 100644
--- a/config/feature_flags/development/ci_needs_optional.yml
+++ b/config/feature_flags/development/ci_needs_optional.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/323891
milestone: '13.10'
type: development
group: group::pipeline authoring
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_o_pipeline_authoring_unique_users_pushing_mr_ciconfigfile.yml b/config/feature_flags/development/usage_data_o_pipeline_authoring_unique_users_pushing_mr_ciconfigfile.yml
index 64e46689775..36fe28236ec 100644
--- a/config/feature_flags/development/usage_data_o_pipeline_authoring_unique_users_pushing_mr_ciconfigfile.yml
+++ b/config/feature_flags/development/usage_data_o_pipeline_authoring_unique_users_pushing_mr_ciconfigfile.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/322166
milestone: '13.10'
type: development
group: group::pipeline authoring
-default_enabled: false
+default_enabled: true
diff --git a/doc/api/members.md b/doc/api/members.md
index b9070b8f305..b917ca98562 100644
--- a/doc/api/members.md
+++ b/doc/api/members.md
@@ -90,8 +90,8 @@ Example response:
Gets a list of group or project members viewable by the authenticated user, including inherited members and permissions through ancestor groups.
-WARNING:
-Due to [an issue](https://gitlab.com/gitlab-org/gitlab/-/issues/249523), the users effective `access_level` may actually be higher than returned value when listing group members.
+If a user is a member of this group or project and also of one or more ancestor groups, only its membership with the highest `access_level` is returned.
+This represents the effective permission of the user.
This function takes pagination parameters `page` and `per_page` to restrict the list of users.
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index d4dc8e7f498..5ed64210725 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -2149,10 +2149,11 @@ To download artifacts from a job in the current pipeline, use the basic form of
#### Optional `needs`
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30680) 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-optional-needs). **(FREE SELF)**
+> - [Deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
+> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/323891) in GitLab 13.11.
+> - Enabled on GitLab.com.
+> - Recommended for production use.
+> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-optional-needs). **(FREE SELF)**
WARNING:
This feature might not be available to you. Check the **version history** note above for details.
@@ -2191,10 +2192,10 @@ rspec:
#### Enable or disable optional needs **(FREE SELF)**
-Optional needs is under development and not ready for production use. It is
-deployed behind a feature flag that is **disabled by default**.
+Optional needs is under development but ready for production use.
+It is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
-can enable it.
+can opt to disable it.
To enable it:
diff --git a/doc/user/analytics/value_stream_analytics.md b/doc/user/analytics/value_stream_analytics.md
index 6c41d93d51f..ea1d76df7ba 100644
--- a/doc/user/analytics/value_stream_analytics.md
+++ b/doc/user/analytics/value_stream_analytics.md
@@ -103,14 +103,8 @@ In short, the Value Stream Analytics dashboard tracks data related to [GitLab fl
## How the production environment is identified
-Value Stream Analytics identifies production environments by looking for project [environments](../../ci/yaml/README.md#environment) with a name matching any of these patterns:
-
-- `prod` or `prod/*`
-- `production` or `production/*`
-
-These patterns are not case-sensitive.
-
-You can change the name of a project environment in your GitLab CI/CD configuration.
+Value Stream Analytics identifies production environments based on
+[the deployment tier of environments](../../ci/environments/index.md#deployment-tier-of-environments).
## Example workflow
diff --git a/doc/user/packages/generic_packages/index.md b/doc/user/packages/generic_packages/index.md
index 2507478345f..57d6245dd96 100644
--- a/doc/user/packages/generic_packages/index.md
+++ b/doc/user/packages/generic_packages/index.md
@@ -47,7 +47,7 @@ PUT /projects/:id/packages/generic/:package_name/:package_version/:file_name?sta
| -------------------| --------------- | ---------| -------------------------------------------------------------------------------------------------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../../../api/README.md#namespaced-path-encoding). |
| `package_name` | string | yes | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`).
-| `package_version` | string | yes | The package version. It can contain only numbers (`0-9`), and dots (`.`). Must be in the format of `X.Y.Z`, i.e. should match `/\A\d+\.\d+\.\d+\z/` regular expression.
+| `package_version` | string | yes | The package version. The following regex validates this: `\A(\.?[\w\+-]+\.?)+\z`. You can test your version strings on [Rubular](https://rubular.com/r/aNCV0wG5K14uq8).
| `file_name` | string | yes | The filename. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`).
| `status` | string | no | The package status. It can be `default` (default) or `hidden`. Hidden packages do not appear in the UI or [package API list endpoints](../../../api/packages.md).
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 1082d63724c..488ba04f87c 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -181,7 +181,7 @@ module Gitlab
end
def generic_package_version_regex
- /\A\d+\.\d+\.\d+\z/
+ maven_version_regex
end
def generic_package_name_regex
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 45aa67b0b15..216c81f3514 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -20593,9 +20593,6 @@ msgstr ""
msgid "New Label"
msgstr ""
-msgid "New Merge Request"
-msgstr ""
-
msgid "New Milestone"
msgstr ""
diff --git a/spec/controllers/admin/impersonations_controller_spec.rb b/spec/controllers/admin/impersonations_controller_spec.rb
index 326003acaf8..744c0712d6b 100644
--- a/spec/controllers/admin/impersonations_controller_spec.rb
+++ b/spec/controllers/admin/impersonations_controller_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe Admin::ImpersonationsController do
context "when the impersonator is not admin (anymore)" do
before do
impersonator.admin = false
- impersonator.save
+ impersonator.save!
end
it "responds with status 404" do
diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb
index cba25dbff95..45ea8949bf2 100644
--- a/spec/controllers/admin/runners_controller_spec.rb
+++ b/spec/controllers/admin/runners_controller_spec.rb
@@ -125,7 +125,7 @@ RSpec.describe Admin::RunnersController do
describe '#resume' do
it 'marks the runner as active and ticks the queue' do
- runner.update(active: false)
+ runner.update!(active: false)
expect do
post :resume, params: { id: runner.id }
@@ -140,7 +140,7 @@ RSpec.describe Admin::RunnersController do
describe '#pause' do
it 'marks the runner as inactive and ticks the queue' do
- runner.update(active: true)
+ runner.update!(active: true)
expect do
post :pause, params: { id: runner.id }
diff --git a/spec/controllers/admin/services_controller_spec.rb b/spec/controllers/admin/services_controller_spec.rb
index 8e78cc75369..d5ec9907b48 100644
--- a/spec/controllers/admin/services_controller_spec.rb
+++ b/spec/controllers/admin/services_controller_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe Admin::ServicesController do
describe "#update" do
let(:project) { create(:project) }
let!(:service_template) do
- RedmineService.create(
+ RedmineService.create!(
project: nil,
active: false,
template: true,
diff --git a/spec/features/merge_request/user_creates_merge_request_spec.rb b/spec/features/merge_request/user_creates_merge_request_spec.rb
index 6b0c7733ab4..119cf31098c 100644
--- a/spec/features/merge_request/user_creates_merge_request_spec.rb
+++ b/spec/features/merge_request/user_creates_merge_request_spec.rb
@@ -87,7 +87,7 @@ RSpec.describe "User creates a merge request", :js do
click_button("Compare branches and continue")
- expect(page).to have_css("h3.page-title", text: "New Merge Request")
+ expect(page).to have_css("h3.page-title", text: "New merge request")
page.within("form#new_merge_request") do
fill_in("Title", with: title)
diff --git a/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb b/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb
index 95e435a333e..d8b258bac47 100644
--- a/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb
+++ b/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe 'New merge request breadcrumb' do
it 'displays link to project merge requests and new merge request' do
page.within '.breadcrumbs' do
- expect(find_link('Merge Requests')[:href]).to end_with(project_merge_requests_path(project))
+ expect(find_link('Merge requests')[:href]).to end_with(project_merge_requests_path(project))
expect(find_link('New')[:href]).to end_with(project_new_merge_request_path(project))
end
end
diff --git a/spec/features/projects/files/user_creates_directory_spec.rb b/spec/features/projects/files/user_creates_directory_spec.rb
index f2074c78dba..46b93d738e1 100644
--- a/spec/features/projects/files/user_creates_directory_spec.rb
+++ b/spec/features/projects/files/user_creates_directory_spec.rb
@@ -77,7 +77,7 @@ RSpec.describe 'Projects > Files > User creates a directory', :js do
it 'creates the directory in the new branch and redirect to the merge request' do
expect(page).to have_content('new-feature')
expect(page).to have_content('The directory has been successfully created')
- expect(page).to have_content('New Merge Request')
+ expect(page).to have_content('New merge request')
expect(page).to have_content('From new-feature into master')
expect(page).to have_content('Add new directory')
diff --git a/spec/finders/group_members_finder_spec.rb b/spec/finders/group_members_finder_spec.rb
index a87a05d4408..3238f6744f7 100644
--- a/spec/finders/group_members_finder_spec.rb
+++ b/spec/finders/group_members_finder_spec.rb
@@ -3,174 +3,180 @@
require 'spec_helper'
RSpec.describe GroupMembersFinder, '#execute' do
- let(:group) { create(:group) }
- let(:nested_group) { create(:group, parent: group) }
- let(:deeper_nested_group) { create(:group, parent: nested_group) }
- let(:user1) { create(:user) }
- let(:user2) { create(:user) }
- let(:user3) { create(:user) }
- let(:user4) { create(:user) }
- let(:user5) { create(:user, :two_factor_via_otp) }
-
- it 'returns members for top-level group' do
- member1 = group.add_maintainer(user1)
- member2 = group.add_maintainer(user2)
- member3 = group.add_maintainer(user3)
- create(:group_member, :minimal_access, user: create(:user), source: group)
-
- result = described_class.new(group).execute
-
- expect(result.to_a).to match_array([member3, member2, member1])
+ let(:group) { create(:group) }
+ let(:sub_group) { create(:group, parent: group) }
+ let(:sub_sub_group) { create(:group, parent: sub_group) }
+ let(:user1) { create(:user) }
+ let(:user2) { create(:user) }
+ let(:user3) { create(:user) }
+ let(:user4) { create(:user) }
+ let(:user5) { create(:user, :two_factor_via_otp) }
+
+ let(:groups) do
+ {
+ group: group,
+ sub_group: sub_group,
+ sub_sub_group: sub_sub_group
+ }
end
- it 'returns members & inherited members for nested group by default' do
- group.add_developer(user2)
- nested_group.request_access(user4)
- member1 = group.add_maintainer(user1)
- member3 = nested_group.add_maintainer(user2)
- member4 = nested_group.add_maintainer(user3)
-
- result = described_class.new(nested_group).execute
-
- expect(result.to_a).to match_array([member1, member3, member4])
+ context 'relations' do
+ let!(:members) do
+ {
+ user1_sub_sub_group: create(:group_member, :maintainer, group: sub_sub_group, user: user1),
+ user1_sub_group: create(:group_member, :developer, group: sub_group, user: user1),
+ user1_group: create(:group_member, :reporter, group: group, user: user1),
+ user2_sub_sub_group: create(:group_member, :reporter, group: sub_sub_group, user: user2),
+ user2_sub_group: create(:group_member, :developer, group: sub_group, user: user2),
+ user2_group: create(:group_member, :maintainer, group: group, user: user2),
+ user3_sub_sub_group: create(:group_member, :developer, group: sub_sub_group, user: user3, expires_at: 1.day.from_now),
+ user3_sub_group: create(:group_member, :developer, group: sub_group, user: user3, expires_at: 2.days.from_now),
+ user3_group: create(:group_member, :reporter, group: group, user: user3),
+ user4_sub_sub_group: create(:group_member, :reporter, group: sub_sub_group, user: user4),
+ user4_sub_group: create(:group_member, :developer, group: sub_group, user: user4, expires_at: 1.day.from_now),
+ user4_group: create(:group_member, :developer, group: group, user: user4, expires_at: 2.days.from_now)
+ }
+ end
+
+ using RSpec::Parameterized::TableSyntax
+
+ where(:subject_relations, :subject_group, :expected_members) do
+ nil | :group | [:user1_group, :user2_group, :user3_group, :user4_group]
+ [:direct] | :group | [:user1_group, :user2_group, :user3_group, :user4_group]
+ [:inherited] | :group | []
+ [:descendants] | :group | [:user1_sub_sub_group, :user2_sub_group, :user3_sub_group, :user4_sub_group]
+ [:direct, :inherited] | :group | [:user1_group, :user2_group, :user3_group, :user4_group]
+ [:direct, :descendants] | :group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:descendants, :inherited] | :group | [:user1_sub_sub_group, :user2_sub_group, :user3_sub_group, :user4_sub_group]
+ [:direct, :descendants, :inherited] | :group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ nil | :sub_group | [:user1_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:direct] | :sub_group | [:user1_sub_group, :user2_sub_group, :user3_sub_group, :user4_sub_group]
+ [:inherited] | :sub_group | [:user1_group, :user2_group, :user3_group, :user4_group]
+ [:descendants] | :sub_group | [:user1_sub_sub_group, :user2_sub_sub_group, :user3_sub_sub_group, :user4_sub_sub_group]
+ [:direct, :inherited] | :sub_group | [:user1_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:direct, :descendants] | :sub_group | [:user1_sub_sub_group, :user2_sub_group, :user3_sub_group, :user4_sub_group]
+ [:descendants, :inherited] | :sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_sub_group, :user4_group]
+ [:direct, :descendants, :inherited] | :sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ nil | :sub_sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:direct] | :sub_sub_group | [:user1_sub_sub_group, :user2_sub_sub_group, :user3_sub_sub_group, :user4_sub_sub_group]
+ [:inherited] | :sub_sub_group | [:user1_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:descendants] | :sub_sub_group | []
+ [:direct, :inherited] | :sub_sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:direct, :descendants] | :sub_sub_group | [:user1_sub_sub_group, :user2_sub_sub_group, :user3_sub_sub_group, :user4_sub_sub_group]
+ [:descendants, :inherited] | :sub_sub_group | [:user1_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ [:direct, :descendants, :inherited] | :sub_sub_group | [:user1_sub_sub_group, :user2_group, :user3_sub_group, :user4_group]
+ end
+
+ with_them do
+ it 'returns correct members' do
+ result = if subject_relations
+ described_class.new(groups[subject_group]).execute(include_relations: subject_relations)
+ else
+ described_class.new(groups[subject_group]).execute
+ end
+
+ expect(result.to_a).to match_array(expected_members.map { |name| members[name] })
+ end
+ end
end
- it 'does not return inherited members for nested group if requested' do
- group.add_maintainer(user1)
- group.add_developer(user2)
- member2 = nested_group.add_maintainer(user2)
- member3 = nested_group.add_maintainer(user3)
+ context 'search' do
+ it 'returns searched members if requested' do
+ group.add_maintainer(user2)
+ group.add_developer(user3)
+ member = group.add_maintainer(user1)
- result = described_class.new(nested_group).execute(include_relations: [:direct])
+ result = described_class.new(group, params: { search: user1.name }).execute
- expect(result.to_a).to match_array([member2, member3])
- end
+ expect(result.to_a).to match_array([member])
+ end
- it 'returns only inherited members for nested group if requested' do
- group.add_developer(user2)
- nested_group.request_access(user4)
- member1 = group.add_maintainer(user1)
- nested_group.add_maintainer(user2)
- nested_group.add_maintainer(user3)
+ it 'returns nothing if search only in inherited relation' do
+ group.add_maintainer(user2)
+ group.add_developer(user3)
+ group.add_maintainer(user1)
- result = described_class.new(nested_group).execute(include_relations: [:inherited])
+ result = described_class.new(group, params: { search: user1.name }).execute(include_relations: [:inherited])
- expect(result.to_a).to match_array([member1])
- end
+ expect(result.to_a).to match_array([])
+ end
- it 'does not return nil if `inherited only` relation is requested on root group' do
- group.add_developer(user2)
+ it 'returns searched member only from sub_group if search only in inherited relation' do
+ group.add_maintainer(user2)
+ group.add_developer(user3)
+ sub_group.add_maintainer(create(:user, name: user1.name))
+ member = group.add_maintainer(user1)
- result = described_class.new(group).execute(include_relations: [:inherited])
+ result = described_class.new(sub_group, params: { search: member.user.name }).execute(include_relations: [:inherited])
- expect(result).not_to be_nil
+ expect(result.to_a).to contain_exactly(member)
+ end
end
- it 'returns members for descendant groups if requested' do
- member1 = group.add_maintainer(user2)
- member2 = group.add_maintainer(user1)
- nested_group.add_maintainer(user2)
- member3 = nested_group.add_maintainer(user3)
- member4 = nested_group.add_maintainer(user4)
+ context 'filter by two-factor' do
+ it 'returns members with two-factor auth if requested by owner' do
+ group.add_owner(user2)
+ group.add_maintainer(user1)
+ member = group.add_maintainer(user5)
- result = described_class.new(group).execute(include_relations: [:direct, :descendants])
+ result = described_class.new(group, user2, params: { two_factor: 'enabled' }).execute
- expect(result.to_a).to match_array([member1, member2, member3, member4])
- end
+ expect(result.to_a).to contain_exactly(member)
+ end
- it 'returns searched members if requested' do
- group.add_maintainer(user2)
- group.add_developer(user3)
- member = group.add_maintainer(user1)
+ it 'returns members without two-factor auth if requested by owner' do
+ member1 = group.add_owner(user2)
+ member2 = group.add_maintainer(user1)
+ member_with_2fa = group.add_maintainer(user5)
- result = described_class.new(group, params: { search: user1.name }).execute
+ result = described_class.new(group, user2, params: { two_factor: 'disabled' }).execute
- expect(result.to_a).to match_array([member])
- end
+ expect(result.to_a).not_to include(member_with_2fa)
+ expect(result.to_a).to match_array([member1, member2])
+ end
- it 'returns nothing if search only in inherited relation' do
- group.add_maintainer(user2)
- group.add_developer(user3)
- group.add_maintainer(user1)
+ it 'returns direct members with two-factor auth if requested by owner' do
+ group.add_owner(user1)
+ group.add_maintainer(user2)
+ sub_group.add_maintainer(user3)
+ member_with_2fa = sub_group.add_maintainer(user5)
- result = described_class.new(group, params: { search: user1.name }).execute(include_relations: [:inherited])
+ result = described_class.new(sub_group, user1, params: { two_factor: 'enabled' }).execute(include_relations: [:direct])
- expect(result.to_a).to match_array([])
- end
+ expect(result.to_a).to match_array([member_with_2fa])
+ end
- it 'returns searched member only from nested_group if search only in inherited relation' do
- group.add_maintainer(user2)
- group.add_developer(user3)
- nested_group.add_maintainer(create(:user, name: user1.name))
- member = group.add_maintainer(user1)
+ it 'returns inherited members with two-factor auth if requested by owner' do
+ group.add_owner(user1)
+ member_with_2fa = group.add_maintainer(user5)
+ sub_group.add_maintainer(user2)
+ sub_group.add_maintainer(user3)
- result = described_class.new(nested_group, params: { search: member.user.name }).execute(include_relations: [:inherited])
+ result = described_class.new(sub_group, user1, params: { two_factor: 'enabled' }).execute(include_relations: [:inherited])
- expect(result.to_a).to contain_exactly(member)
- end
-
- it 'returns members with two-factor auth if requested by owner' do
- group.add_owner(user2)
- group.add_maintainer(user1)
- member = group.add_maintainer(user5)
-
- result = described_class.new(group, user2, params: { two_factor: 'enabled' }).execute
+ expect(result.to_a).to match_array([member_with_2fa])
+ end
- expect(result.to_a).to contain_exactly(member)
- end
-
- it 'returns members without two-factor auth if requested by owner' do
- member1 = group.add_owner(user2)
- member2 = group.add_maintainer(user1)
- member_with_2fa = group.add_maintainer(user5)
+ it 'returns direct members without two-factor auth if requested by owner' do
+ group.add_owner(user1)
+ group.add_maintainer(user2)
+ member3 = sub_group.add_maintainer(user3)
+ sub_group.add_maintainer(user5)
- result = described_class.new(group, user2, params: { two_factor: 'disabled' }).execute
+ result = described_class.new(sub_group, user1, params: { two_factor: 'disabled' }).execute(include_relations: [:direct])
- expect(result.to_a).not_to include(member_with_2fa)
- expect(result.to_a).to match_array([member1, member2])
- end
-
- it 'returns direct members with two-factor auth if requested by owner' do
- group.add_owner(user1)
- group.add_maintainer(user2)
- nested_group.add_maintainer(user3)
- member_with_2fa = nested_group.add_maintainer(user5)
-
- result = described_class.new(nested_group, user1, params: { two_factor: 'enabled' }).execute(include_relations: [:direct])
-
- expect(result.to_a).to match_array([member_with_2fa])
- end
-
- it 'returns inherited members with two-factor auth if requested by owner' do
- group.add_owner(user1)
- member_with_2fa = group.add_maintainer(user5)
- nested_group.add_maintainer(user2)
- nested_group.add_maintainer(user3)
-
- result = described_class.new(nested_group, user1, params: { two_factor: 'enabled' }).execute(include_relations: [:inherited])
-
- expect(result.to_a).to match_array([member_with_2fa])
- end
-
- it 'returns direct members without two-factor auth if requested by owner' do
- group.add_owner(user1)
- group.add_maintainer(user2)
- member3 = nested_group.add_maintainer(user3)
- nested_group.add_maintainer(user5)
-
- result = described_class.new(nested_group, user1, params: { two_factor: 'disabled' }).execute(include_relations: [:direct])
-
- expect(result.to_a).to match_array([member3])
- end
+ expect(result.to_a).to match_array([member3])
+ end
- it 'returns inherited members without two-factor auth if requested by owner' do
- member1 = group.add_owner(user1)
- group.add_maintainer(user5)
- nested_group.add_maintainer(user2)
- nested_group.add_maintainer(user3)
+ it 'returns inherited members without two-factor auth if requested by owner' do
+ member1 = group.add_owner(user1)
+ group.add_maintainer(user5)
+ sub_group.add_maintainer(user2)
+ sub_group.add_maintainer(user3)
- result = described_class.new(nested_group, user1, params: { two_factor: 'disabled' }).execute(include_relations: [:inherited])
+ result = described_class.new(sub_group, user1, params: { two_factor: 'disabled' }).execute(include_relations: [:inherited])
- expect(result.to_a).to match_array([member1])
+ expect(result.to_a).to match_array([member1])
+ end
end
end
diff --git a/spec/frontend/boards/components/board_add_new_column_spec.js b/spec/frontend/boards/components/board_add_new_column_spec.js
index 60584eaf6cf..61f210f566b 100644
--- a/spec/frontend/boards/components/board_add_new_column_spec.js
+++ b/spec/frontend/boards/components/board_add_new_column_spec.js
@@ -1,3 +1,4 @@
+import { GlFormRadioGroup } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
@@ -12,6 +13,10 @@ Vue.use(Vuex);
describe('Board card layout', () => {
let wrapper;
+ const selectLabel = (id) => {
+ wrapper.findComponent(GlFormRadioGroup).vm.$emit('change', id);
+ };
+
const createStore = ({ actions = {}, getters = {}, state = {} } = {}) => {
return new Vuex.Store({
state: {
@@ -57,6 +62,11 @@ describe('Board card layout', () => {
},
}),
);
+
+ // trigger change event
+ if (selectedId) {
+ selectLabel(selectedId);
+ }
};
afterEach(() => {
diff --git a/spec/frontend/diffs/store/getters_spec.js b/spec/frontend/diffs/store/getters_spec.js
index 04606b48662..2e3a66d5b01 100644
--- a/spec/frontend/diffs/store/getters_spec.js
+++ b/spec/frontend/diffs/store/getters_spec.js
@@ -377,32 +377,40 @@ describe('Diffs Module Getters', () => {
});
describe('suggestionCommitMessage', () => {
+ let rootState;
+
beforeEach(() => {
Object.assign(localState, {
defaultSuggestionCommitMessage:
'%{branch_name}%{project_path}%{project_name}%{username}%{user_full_name}%{file_paths}%{suggestions_count}%{files_count}',
- branchName: 'branch',
- projectPath: '/path',
- projectName: 'name',
- username: 'user',
- userFullName: 'user userton',
});
+ rootState = {
+ page: {
+ mrMetadata: {
+ branch_name: 'branch',
+ project_path: '/path',
+ project_name: 'name',
+ username: 'user',
+ user_full_name: 'user userton',
+ },
+ },
+ };
});
it.each`
- specialState | output
- ${{}} | ${'branch/pathnameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'}
- ${{ userFullName: null }} | ${'branch/pathnameuser%{user_full_name}%{file_paths}%{suggestions_count}%{files_count}'}
- ${{ username: null }} | ${'branch/pathname%{username}user userton%{file_paths}%{suggestions_count}%{files_count}'}
- ${{ projectName: null }} | ${'branch/path%{project_name}useruser userton%{file_paths}%{suggestions_count}%{files_count}'}
- ${{ projectPath: null }} | ${'branch%{project_path}nameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'}
- ${{ branchName: null }} | ${'%{branch_name}/pathnameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'}
+ specialState | output
+ ${{}} | ${'branch/pathnameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'}
+ ${{ user_full_name: null }} | ${'branch/pathnameuser%{user_full_name}%{file_paths}%{suggestions_count}%{files_count}'}
+ ${{ username: null }} | ${'branch/pathname%{username}user userton%{file_paths}%{suggestions_count}%{files_count}'}
+ ${{ project_name: null }} | ${'branch/path%{project_name}useruser userton%{file_paths}%{suggestions_count}%{files_count}'}
+ ${{ project_path: null }} | ${'branch%{project_path}nameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'}
+ ${{ branch_name: null }} | ${'%{branch_name}/pathnameuseruser userton%{file_paths}%{suggestions_count}%{files_count}'}
`(
'provides the correct "base" default commit message based on state ($specialState)',
({ specialState, output }) => {
- Object.assign(localState, specialState);
+ Object.assign(rootState.page.mrMetadata, specialState);
- expect(getters.suggestionCommitMessage(localState)()).toBe(output);
+ expect(getters.suggestionCommitMessage(localState, null, rootState)()).toBe(output);
},
);
@@ -417,7 +425,9 @@ describe('Diffs Module Getters', () => {
`(
"properly overrides state values ($stateOverrides) if they're provided",
({ stateOverrides, output }) => {
- expect(getters.suggestionCommitMessage(localState)(stateOverrides)).toBe(output);
+ expect(getters.suggestionCommitMessage(localState, null, rootState)(stateOverrides)).toBe(
+ output,
+ );
},
);
@@ -431,7 +441,9 @@ describe('Diffs Module Getters', () => {
`(
"fills in any missing interpolations ($providedValues) when they're provided at the getter callsite",
({ providedValues, output }) => {
- expect(getters.suggestionCommitMessage(localState)(providedValues)).toBe(output);
+ expect(getters.suggestionCommitMessage(localState, null, rootState)(providedValues)).toBe(
+ output,
+ );
},
);
});
diff --git a/spec/frontend/error_tracking/components/error_tracking_list_spec.js b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
index c6ce236af01..c0c542ae587 100644
--- a/spec/frontend/error_tracking/components/error_tracking_list_spec.js
+++ b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
@@ -52,7 +52,6 @@ describe('ErrorTrackingList', () => {
beforeEach(() => {
actions = {
- getErrorList: () => {},
startPolling: jest.fn(),
restartPolling: jest.fn().mockName('restartPolling'),
addRecentSearch: jest.fn(),
diff --git a/spec/frontend/notes/components/note_body_spec.js b/spec/frontend/notes/components/note_body_spec.js
index 4922de987fa..40251244423 100644
--- a/spec/frontend/notes/components/note_body_spec.js
+++ b/spec/frontend/notes/components/note_body_spec.js
@@ -81,14 +81,21 @@ describe('issue_note_body component', () => {
state: {
defaultSuggestionCommitMessage:
'%{branch_name}%{project_path}%{project_name}%{username}%{user_full_name}%{file_paths}%{suggestions_count}%{files_count}',
- branchName: 'branch',
- projectPath: '/path',
- projectName: 'name',
- username: 'user',
- userFullName: 'user userton',
},
getters: { suggestionCommitMessage },
},
+ page: {
+ namespaced: true,
+ state: {
+ mrMetadata: {
+ branch_name: 'branch',
+ project_path: '/path',
+ project_name: 'name',
+ username: 'user',
+ user_full_name: 'user userton',
+ },
+ },
+ },
},
});
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index 1aca3dae41b..f62a3c74005 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -667,7 +667,14 @@ RSpec.describe Gitlab::Regex do
it { is_expected.to match('1.2.3') }
it { is_expected.to match('1.3.350') }
- it { is_expected.not_to match('1.3.350-20201230123456') }
+ it { is_expected.to match('1.3.350-20201230123456') }
+ it { is_expected.to match('1.2.3-rc1') }
+ it { is_expected.to match('1.2.3g') }
+ it { is_expected.to match('1.2') }
+ it { is_expected.to match('1.2.bananas') }
+ it { is_expected.to match('v1.2.4-build') }
+ it { is_expected.to match('d50d836eb3de6177ce6c7a5482f27f9c2c84b672') }
+ it { is_expected.to match('this_is_a_string_only') }
it { is_expected.not_to match('..1.2.3') }
it { is_expected.not_to match(' 1.2.3') }
it { is_expected.not_to match("1.2.3 \r\t") }
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index c0afc1d50f6..7398a343ef4 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -808,4 +808,30 @@ RSpec.describe Deployment do
end
end
end
+
+ describe '#update_merge_request_metrics!' do
+ let_it_be(:project) { create(:project, :repository) }
+ let(:environment) { build(:environment, environment_tier, project: project) }
+ let!(:deployment) { create(:deployment, :success, project: project, environment: environment) }
+ let!(:merge_request) { create(:merge_request, :simple, :merged_last_month, project: project) }
+
+ context 'with production environment' do
+ let(:environment_tier) { :production }
+
+ it 'updates merge request metrics for production-grade environment' do
+ expect { deployment.update_merge_request_metrics! }
+ .to change { merge_request.reload.metrics.first_deployed_to_production_at }
+ .from(nil).to(deployment.reload.finished_at)
+ end
+ end
+
+ context 'with staging environment' do
+ let(:environment_tier) { :staging }
+
+ it 'updates merge request metrics for production-grade environment' do
+ expect { deployment.update_merge_request_metrics! }
+ .not_to change { merge_request.reload.metrics.first_deployed_to_production_at }
+ end
+ end
+ end
end
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index e021a6cf6d3..759bb080172 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -302,6 +302,8 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
'testing' | described_class.tiers[:testing]
'testing-prd' | described_class.tiers[:testing]
'acceptance-testing' | described_class.tiers[:testing]
+ 'production-test' | described_class.tiers[:testing]
+ 'test-production' | described_class.tiers[:testing]
'QC' | described_class.tiers[:testing]
'gstg' | described_class.tiers[:staging]
'staging' | described_class.tiers[:staging]
@@ -315,6 +317,12 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
'gprd-cny' | described_class.tiers[:production]
'production' | described_class.tiers[:production]
'Production' | described_class.tiers[:production]
+ 'PRODUCTION' | described_class.tiers[:production]
+ 'Production/eu' | described_class.tiers[:production]
+ 'production/eu' | described_class.tiers[:production]
+ 'PRODUCTION/EU' | described_class.tiers[:production]
+ 'productioneu' | described_class.tiers[:production]
+ 'production/www.gitlab.com' | described_class.tiers[:production]
'prod' | described_class.tiers[:production]
'PROD' | described_class.tiers[:production]
'Live' | described_class.tiers[:production]
@@ -444,31 +452,6 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
end
end
- describe '#update_merge_request_metrics?' do
- {
- 'gprd' => false,
- 'prod' => true,
- 'prod-test' => false,
- 'PROD' => true,
- 'production' => true,
- 'production-test' => false,
- 'PRODUCTION' => true,
- 'production/eu' => true,
- 'PRODUCTION/EU' => true,
- 'production/www.gitlab.com' => true,
- 'productioneu' => false,
- 'Production' => true,
- 'Production/eu' => true,
- 'test-production' => false
- }.each do |name, expected_value|
- it "returns #{expected_value} for #{name}" do
- env = create(:environment, name: name)
-
- expect(env.update_merge_request_metrics?).to eq(expected_value), "Expected the name '#{name}' to result in #{expected_value}, but it didn't."
- end
- end
- end
-
describe '#environment_type' do
subject { environment.environment_type }
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index c41f466456f..05247cf9f04 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -413,6 +413,24 @@ RSpec.describe Member do
it { is_expected.not_to include @blocked_developer }
it { is_expected.not_to include @member_with_minimal_access }
end
+
+ describe '.distinct_on_user_with_max_access_level' do
+ let_it_be(:other_group) { create(:group) }
+ let_it_be(:member_with_lower_access_level) { create(:group_member, :developer, group: other_group, user: @owner_user) }
+
+ subject { described_class.default_scoped.distinct_on_user_with_max_access_level.to_a }
+
+ it { is_expected.not_to include member_with_lower_access_level }
+ it { is_expected.to include @owner }
+ it { is_expected.to include @maintainer }
+ it { is_expected.to include @invited_member }
+ it { is_expected.to include @accepted_invite_member }
+ it { is_expected.to include @requested_member }
+ it { is_expected.to include @accepted_request_member }
+ it { is_expected.to include @blocked_maintainer }
+ it { is_expected.to include @blocked_developer }
+ it { is_expected.to include @member_with_minimal_access }
+ end
end
describe "Delegate methods" do
diff --git a/spec/models/packages/package_spec.rb b/spec/models/packages/package_spec.rb
index 2ea4c5d8211..cf52749a186 100644
--- a/spec/models/packages/package_spec.rb
+++ b/spec/models/packages/package_spec.rb
@@ -367,7 +367,14 @@ RSpec.describe Packages::Package, type: :model do
it { is_expected.to validate_presence_of(:version) }
it { is_expected.to allow_value('1.2.3').for(:version) }
it { is_expected.to allow_value('1.3.350').for(:version) }
- it { is_expected.not_to allow_value('1.3.350-20201230123456').for(:version) }
+ it { is_expected.to allow_value('1.3.350-20201230123456').for(:version) }
+ it { is_expected.to allow_value('1.2.3-rc1').for(:version) }
+ it { is_expected.to allow_value('1.2.3g').for(:version) }
+ it { is_expected.to allow_value('1.2').for(:version) }
+ it { is_expected.to allow_value('1.2.bananas').for(:version) }
+ it { is_expected.to allow_value('v1.2.4-build').for(:version) }
+ it { is_expected.to allow_value('d50d836eb3de6177ce6c7a5482f27f9c2c84b672').for(:version) }
+ it { is_expected.to allow_value('this_is_a_string_only').for(:version) }
it { is_expected.not_to allow_value('..1.2.3').for(:version) }
it { is_expected.not_to allow_value(' 1.2.3').for(:version) }
it { is_expected.not_to allow_value("1.2.3 \r\t").for(:version) }
diff --git a/spec/requests/api/generic_packages_spec.rb b/spec/requests/api/generic_packages_spec.rb
index 16d56b6cfbe..a5e40eec919 100644
--- a/spec/requests/api/generic_packages_spec.rb
+++ b/spec/requests/api/generic_packages_spec.rb
@@ -16,6 +16,7 @@ RSpec.describe API::GenericPackages do
let_it_be(:project_deploy_token_ro) { create(:project_deploy_token, deploy_token: deploy_token_ro, project: project) }
let_it_be(:deploy_token_wo) { create(:deploy_token, read_package_registry: false, write_package_registry: true) }
let_it_be(:project_deploy_token_wo) { create(:project_deploy_token, deploy_token: deploy_token_wo, project: project) }
+
let(:user) { personal_access_token.user }
let(:ci_build) { create(:ci_build, :running, user: user) }
@@ -326,6 +327,34 @@ RSpec.describe API::GenericPackages do
end
end
end
+
+ context 'different versions' do
+ where(:version, :expected_status) do
+ '1.3.350-20201230123456' | :created
+ '1.2.3' | :created
+ '1.2.3g' | :created
+ '1.2' | :created
+ '1.2.bananas' | :created
+ 'v1.2.4-build' | :created
+ 'd50d836eb3de6177ce6c7a5482f27f9c2c84b672' | :created
+ '..1.2.3' | :bad_request
+ '1.2.3-4/../../' | :bad_request
+ '%2e%2e%2f1.2.3' | :bad_request
+ end
+
+ with_them do
+ let(:expected_package_diff_count) { expected_status == :created ? 1 : 0 }
+ let(:headers) { workhorse_headers.merge(auth_header) }
+
+ subject { upload_file(params, headers, package_version: version) }
+
+ it "returns the #{params[:expected_status]}", :aggregate_failures do
+ expect { subject }.to change { project.packages.generic.count }.by(expected_package_diff_count)
+
+ expect(response).to have_gitlab_http_status(expected_status)
+ end
+ end
+ end
end
end
@@ -418,8 +447,8 @@ RSpec.describe API::GenericPackages do
end
end
- def upload_file(params, request_headers, send_rewritten_field: true, package_name: 'mypackage', file_name: 'myfile.tar.gz')
- url = "/projects/#{project.id}/packages/generic/#{package_name}/0.0.1/#{file_name}"
+ def upload_file(params, request_headers, send_rewritten_field: true, package_name: 'mypackage', package_version: '0.0.1', file_name: 'myfile.tar.gz')
+ url = "/projects/#{project.id}/packages/generic/#{package_name}/#{package_version}/#{file_name}"
workhorse_finalize(
api(url),