Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/confirm_danger_modal.js57
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue22
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js3
-rw-r--r--app/helpers/projects_helper.rb4
-rw-r--r--app/serializers/merge_request_poll_cached_widget_entity.rb4
-rw-r--r--app/views/projects/_visibility_modal.html.haml30
-rw-r--r--app/views/projects/edit.html.haml4
-rw-r--r--app/views/projects/merge_requests/_widget.html.haml1
-rw-r--r--changelogs/unreleased/11506-add-additional-attributes-and-arguments-for-the-graphql-epic-query.yml5
-rw-r--r--changelogs/unreleased/31236-auto-update-merge-widget.yml5
-rw-r--r--changelogs/unreleased/37952-fix-missing-empty-rule-ux-in-mr-widget.yml5
-rw-r--r--changelogs/unreleased/ph-33358-projectVisibilityConfirmModal.yml5
-rw-r--r--changelogs/unreleased/remove-action-buttons-if-no-designs.yml5
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql10
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json36
-rw-r--r--doc/api/graphql/reference/index.md2
-rw-r--r--doc/development/gitaly.md79
-rw-r--r--doc/public_access/img/project_visibility_confirmation_v12_6.pngbin0 -> 101511 bytes
-rw-r--r--doc/public_access/public_access.md10
-rw-r--r--doc/user/project/settings/index.md4
-rw-r--r--lib/tasks/gitlab/import_export/import.rake4
-rw-r--r--locale/gitlab.pot18
-rw-r--r--package.json6
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb24
-rw-r--r--spec/features/projects/user_changes_project_visibility_spec.rb46
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_poll_cached_widget.json1
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js27
-rw-r--r--yarn.lock28
29 files changed, 399 insertions, 49 deletions
diff --git a/app/assets/javascripts/confirm_danger_modal.js b/app/assets/javascripts/confirm_danger_modal.js
index 1000c310e35..262d501bfba 100644
--- a/app/assets/javascripts/confirm_danger_modal.js
+++ b/app/assets/javascripts/confirm_danger_modal.js
@@ -1,39 +1,54 @@
import $ from 'jquery';
import { rstrip } from './lib/utils/common_utils';
-function openConfirmDangerModal($form, text) {
- const $input = $('.js-confirm-danger-input');
+function openConfirmDangerModal($form, $modal, text) {
+ const $input = $('.js-confirm-danger-input', $modal);
$input.val('');
- $('.js-confirm-text').text(text || '');
- $('#modal-confirm-danger').modal('show');
+ $('.js-confirm-text', $modal).text(text || '');
+ $modal.modal('show');
- const confirmTextMatch = $('.js-confirm-danger-match').text();
- const $submit = $('.js-confirm-danger-submit');
+ const confirmTextMatch = $('.js-confirm-danger-match', $modal).text();
+ const $submit = $('.js-confirm-danger-submit', $modal);
$submit.disable();
$input.focus();
- $('.js-confirm-danger-input')
- .off('input')
- .on('input', function handleInput() {
- const confirmText = rstrip($(this).val());
- if (confirmText === confirmTextMatch) {
- $submit.enable();
- } else {
- $submit.disable();
- }
- });
- $('.js-confirm-danger-submit')
+ $input.off('input').on('input', function handleInput() {
+ const confirmText = rstrip($(this).val());
+ if (confirmText === confirmTextMatch) {
+ $submit.enable();
+ } else {
+ $submit.disable();
+ }
+ });
+ $('.js-confirm-danger-submit', $modal)
.off('click')
.on('click', () => $form.submit());
}
+function getModal($btn) {
+ const $modal = $btn.prev('.modal');
+
+ if ($modal.length) {
+ return $modal;
+ }
+
+ return $('#modal-confirm-danger');
+}
+
export default function initConfirmDangerModal() {
$(document).on('click', '.js-confirm-danger', e => {
- e.preventDefault();
const $btn = $(e.target);
- const $form = $btn.closest('form');
- const text = $btn.data('confirmDangerMessage');
- openConfirmDangerModal($form, text);
+ const checkFieldName = $btn.data('checkFieldName');
+ const checkFieldCompareValue = $btn.data('checkCompareValue');
+ const checkFieldVal = parseInt($(`[name="${checkFieldName}"]`).val(), 10);
+
+ if (!checkFieldName || checkFieldVal < checkFieldCompareValue) {
+ e.preventDefault();
+ const $form = $btn.closest('form');
+ const $modal = getModal($btn);
+ const text = $btn.data('confirmDangerMessage');
+ openConfirmDangerModal($form, $modal, text);
+ }
});
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
index aa65b16a3c3..65e523715e2 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
@@ -3,8 +3,9 @@ import _ from 'underscore';
import successSvg from 'icons/_icon_status_success.svg';
import warningSvg from 'icons/_icon_status_warning.svg';
import simplePoll from '~/lib/utils/simple_poll';
-import { __ } from '~/locale';
+import { __, sprintf } from '~/locale';
import readyToMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/ready_to_merge';
+import { GlIcon } from '@gitlab/ui';
import MergeRequest from '../../../merge_request';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import Flash from '../../../flash';
@@ -24,6 +25,7 @@ export default {
CommitsHeader,
CommitEdit,
CommitMessageDropdown,
+ GlIcon,
},
mixins: [readyToMergeMixin],
props: {
@@ -111,6 +113,18 @@ export default {
shouldShowMergeEdit() {
return !this.mr.ffOnlyEnabled;
},
+ shaMismatchLink() {
+ const href = this.mr.mergeRequestDiffsPath;
+
+ return sprintf(
+ __('New changes were added. %{linkStart}Reload the page to review them%{linkEnd}'),
+ {
+ linkStart: `<a href="${href}">`,
+ linkEnd: '</a>',
+ },
+ false,
+ );
+ },
},
methods: {
updateMergeCommitMessage(includeDescription) {
@@ -123,7 +137,7 @@ export default {
}
const options = {
- sha: this.mr.sha,
+ sha: this.mr.latestSHA || this.mr.sha,
commit_message: this.commitMessage,
auto_merge_strategy: useAutoMerge ? this.mr.preferredAutoMergeStrategy : undefined,
should_remove_source_branch: this.removeSourceBranch === true,
@@ -314,6 +328,10 @@ export default {
</template>
</div>
</div>
+ <div v-if="mr.isSHAMismatch" class="d-flex align-items-center mt-2 js-sha-mismatch">
+ <gl-icon name="warning-solid" class="text-warning mr-1" />
+ <span class="text-warning" v-html="shaMismatchLink"></span>
+ </div>
</div>
</div>
<template v-if="shouldShowMergeControls">
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 31dbddbd21a..4861588992c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -25,7 +25,6 @@ import NothingToMergeState from './components/states/nothing_to_merge.vue';
import MissingBranchState from './components/states/mr_widget_missing_branch.vue';
import NotAllowedState from './components/states/mr_widget_not_allowed.vue';
import ReadyToMergeState from './components/states/ready_to_merge.vue';
-import ShaMismatchState from './components/states/sha_mismatch.vue';
import UnresolvedDiscussionsState from './components/states/unresolved_discussions.vue';
import PipelineBlockedState from './components/states/mr_widget_pipeline_blocked.vue';
import PipelineFailedState from './components/states/pipeline_failed.vue';
@@ -63,7 +62,7 @@ export default {
'mr-widget-not-allowed': NotAllowedState,
'mr-widget-missing-branch': MissingBranchState,
'mr-widget-ready-to-merge': ReadyToMergeState,
- 'sha-mismatch': ShaMismatchState,
+ 'sha-mismatch': ReadyToMergeState,
'mr-widget-checking': CheckingState,
'mr-widget-unresolved-discussions': UnresolvedDiscussionsState,
'mr-widget-pipeline-blocked': PipelineBlockedState,
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 7e5b8f14b96..4c178950ec1 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -48,6 +48,7 @@ export default class MergeRequestStore {
this.commits = data.commits_without_merge_commits || [];
this.squashCommitMessage = data.default_squash_commit_message;
this.rebaseInProgress = data.rebase_in_progress;
+ this.mergeRequestDiffsPath = data.diffs_path;
if (data.issues_links) {
const links = data.issues_links;
@@ -81,6 +82,7 @@ export default class MergeRequestStore {
this.isOpen = data.state === 'opened';
this.hasMergeableDiscussionsState = data.mergeable_discussions_state === false;
this.isSHAMismatch = this.sha !== data.diff_head_sha;
+ this.latestSHA = data.diff_head_sha;
this.canBeMerged = data.can_be_merged || false;
this.isMergeAllowed = data.mergeable || false;
this.mergeOngoing = data.merge_ongoing;
@@ -170,6 +172,7 @@ export default class MergeRequestStore {
this.conflictsDocsPath = data.conflicts_docs_path;
this.ciEnvironmentsStatusPath = data.ci_environments_status_path;
this.securityApprovalsHelpPagePath = data.security_approvals_help_page_path;
+ this.eligibleApproversDocsPath = data.eligible_approvers_docs_path;
}
get isNothingToMergeState() {
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index ff013f3f7ec..c7fdd009edb 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -699,4 +699,8 @@ module ProjectsHelper
def vue_file_list_enabled?
Feature.enabled?(:vue_file_list, @project)
end
+
+ def show_visibility_confirm_modal?(project)
+ project.unlink_forks_upon_visibility_decrease_enabled? && project.visibility_level > Gitlab::VisibilityLevel::PRIVATE && project.forks_count > 0
+ end
end
diff --git a/app/serializers/merge_request_poll_cached_widget_entity.rb b/app/serializers/merge_request_poll_cached_widget_entity.rb
index c7dc8c43a9a..2f8eb6650e8 100644
--- a/app/serializers/merge_request_poll_cached_widget_entity.rb
+++ b/app/serializers/merge_request_poll_cached_widget_entity.rb
@@ -70,6 +70,10 @@ class MergeRequestPollCachedWidgetEntity < IssuableEntity
presenter(merge_request).source_branch_with_namespace_link
end
+ expose :diffs_path do |merge_request|
+ diffs_project_merge_request_path(merge_request.project, merge_request)
+ end
+
private
delegate :current_user, to: :request
diff --git a/app/views/projects/_visibility_modal.html.haml b/app/views/projects/_visibility_modal.html.haml
new file mode 100644
index 00000000000..3ef93a40137
--- /dev/null
+++ b/app/views/projects/_visibility_modal.html.haml
@@ -0,0 +1,30 @@
+- strong_start = "<strong>".html_safe
+- strong_end = "</strong>".html_safe
+
+.modal.js-confirm-project-visiblity{ tabindex: -1 }
+ .modal-dialog
+ .modal-content
+ .modal-header
+ %h3.page-title= _('Reduce this project’s visibility?')
+ %button.close{ type: "button", "data-dismiss": "modal", "aria-label" => _('Close') }
+ %span{ "aria-hidden": true }= sprite_icon("close", size: 16)
+ .modal-body
+ %p
+ - if @project.group
+ = _("You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end} in %{strong_start}%{group_name}%{strong_end}.").html_safe % { project_name: @project.name, group_name: @project.group.name, strong_start: strong_start, strong_end: strong_end }
+ - else
+ = _("You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end}.").html_safe % { project_name: @project.name, strong_start: strong_start, strong_end: strong_end }
+ %p
+ = _('Once you confirm and press "Reduce project visibility":')
+ %ul
+ %li
+ = ("Current forks will keep their visibility level but their fork relationship with this project will be %{strong_start}removed%{strong_end}.").html_safe % { strong_start: strong_start, strong_end: strong_end }
+ %label{ for: "confirm_path_input" }
+ = ("To confirm, type %{phrase_code}").html_safe % { phrase_code: '<code class="js-confirm-danger-match">%{phrase_name}</code>'.html_safe % { phrase_name: @project.full_path } }
+ .form-group
+ = text_field_tag 'confirm_path_input', '', class: 'form-control js-confirm-danger-input qa-confirm-input'
+ .form-actions.clearfix
+ .pull-right
+ %button.btn.btn-default{ type: "button", "data-dismiss": "modal" }
+ = _('Cancel')
+ = submit_tag _('Reduce project visibility'), class: "btn btn-danger js-confirm-danger-submit qa-confirm-button", disabled: true
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 328fdd0be10..7ad52673137 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -21,7 +21,9 @@
%input{ name: 'update_section', type: 'hidden', value: 'js-shared-permissions' }
%template.js-project-permissions-form-data{ type: "application/json" }= project_permissions_panel_data_json(@project)
.js-project-permissions-form
- = f.submit _('Save changes'), class: "btn btn-success", data: { qa_selector: 'visibility_features_permissions_save_button' }
+ - if show_visibility_confirm_modal?(@project)
+ = render "visibility_modal"
+ = f.submit _('Save changes'), class: "btn btn-success #{('js-confirm-danger' if show_visibility_confirm_modal?(@project))}", data: { qa_selector: 'visibility_features_permissions_save_button', check_field_name: ("project[visibility_level]" if show_visibility_confirm_modal?(@project)), check_compare_value: @project.visibility_level }
%section.qa-merge-request-settings.rspec-merge-request-settings.settings.merge-requests-feature.no-animate#js-merge-request-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)] }
.settings-header
diff --git a/app/views/projects/merge_requests/_widget.html.haml b/app/views/projects/merge_requests/_widget.html.haml
index f056189fec0..b00c95c3cd7 100644
--- a/app/views/projects/merge_requests/_widget.html.haml
+++ b/app/views/projects/merge_requests/_widget.html.haml
@@ -9,5 +9,6 @@
window.gl.mrWidgetData.squash_before_merge_help_path = '#{help_page_path("user/project/merge_requests/squash_and_merge")}';
window.gl.mrWidgetData.troubleshooting_docs_path = '#{help_page_path('user/project/merge_requests/index.md', anchor: 'troubleshooting')}';
window.gl.mrWidgetData.security_approvals_help_page_path = '#{help_page_path('user/application_security/index.html', anchor: 'security-approvals-in-merge-requests-ultimate')}';
+ window.gl.mrWidgetData.eligible_approvers_docs_path = '#{help_page_path('user/project/merge_requests/merge_request_approvals', anchor: 'eligible-approvers')}';
#js-vue-mr-widget.mr-widget
diff --git a/changelogs/unreleased/11506-add-additional-attributes-and-arguments-for-the-graphql-epic-query.yml b/changelogs/unreleased/11506-add-additional-attributes-and-arguments-for-the-graphql-epic-query.yml
new file mode 100644
index 00000000000..a3bf40ce76f
--- /dev/null
+++ b/changelogs/unreleased/11506-add-additional-attributes-and-arguments-for-the-graphql-epic-query.yml
@@ -0,0 +1,5 @@
+---
+title: Add upvote/downvotes attributes to GraphQL Epic query
+merge_request: 14311
+author:
+type: added
diff --git a/changelogs/unreleased/31236-auto-update-merge-widget.yml b/changelogs/unreleased/31236-auto-update-merge-widget.yml
new file mode 100644
index 00000000000..b84e3e2c15b
--- /dev/null
+++ b/changelogs/unreleased/31236-auto-update-merge-widget.yml
@@ -0,0 +1,5 @@
+---
+title: Allow merge without refresh when new commits are pushed
+merge_request: 19725
+author:
+type: changed
diff --git a/changelogs/unreleased/37952-fix-missing-empty-rule-ux-in-mr-widget.yml b/changelogs/unreleased/37952-fix-missing-empty-rule-ux-in-mr-widget.yml
new file mode 100644
index 00000000000..caec491fa67
--- /dev/null
+++ b/changelogs/unreleased/37952-fix-missing-empty-rule-ux-in-mr-widget.yml
@@ -0,0 +1,5 @@
+---
+title: Resolve Add missing popover and remove none in MR widget
+merge_request: 21095
+author:
+type: other
diff --git a/changelogs/unreleased/ph-33358-projectVisibilityConfirmModal.yml b/changelogs/unreleased/ph-33358-projectVisibilityConfirmModal.yml
new file mode 100644
index 00000000000..2f9e2e76cff
--- /dev/null
+++ b/changelogs/unreleased/ph-33358-projectVisibilityConfirmModal.yml
@@ -0,0 +1,5 @@
+---
+title: Asks for confirmation before changing project visibility level
+merge_request: 20170
+author:
+type: added
diff --git a/changelogs/unreleased/remove-action-buttons-if-no-designs.yml b/changelogs/unreleased/remove-action-buttons-if-no-designs.yml
new file mode 100644
index 00000000000..876ce5e5f00
--- /dev/null
+++ b/changelogs/unreleased/remove-action-buttons-if-no-designs.yml
@@ -0,0 +1,5 @@
+---
+title: Remove action buttons from designs tab if there are no designs
+merge_request: 21186
+author:
+type: fixed
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 6852e0016b0..8abe501eafc 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -1230,6 +1230,11 @@ type Epic implements Noteable {
"""
last: Int
): DiscussionConnection!
+
+ """
+ Number of downvotes the epic has received
+ """
+ downvotes: Int!
dueDate: Time
dueDateFixed: Time
dueDateFromMilestones: Time
@@ -1361,6 +1366,11 @@ type Epic implements Noteable {
updatedAt: Time
"""
+ Number of upvotes the epic has received
+ """
+ upvotes: Int!
+
+ """
Permissions for the current user on the resource
"""
userPermissions: EpicPermissions!
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index f2cf473c1f3..aa75d920997 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -3631,6 +3631,24 @@
"deprecationReason": null
},
{
+ "name": "downvotes",
+ "description": "Number of downvotes the epic has received",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "dueDate",
"description": null,
"args": [
@@ -4182,6 +4200,24 @@
"deprecationReason": null
},
{
+ "name": "upvotes",
+ "description": "Number of upvotes the epic has received",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "userPermissions",
"description": "Permissions for the current user on the resource",
"args": [
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 095d14ed4d5..e9c27ffc432 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -211,6 +211,8 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `dueDateIsFixed` | Boolean | |
| `dueDateFixed` | Time | |
| `dueDateFromMilestones` | Time | |
+| `upvotes` | Int! | Number of upvotes the epic has received |
+| `downvotes` | Int! | Number of downvotes the epic has received |
| `closedAt` | Time | |
| `createdAt` | Time | |
| `updatedAt` | Time | |
diff --git a/doc/development/gitaly.md b/doc/development/gitaly.md
index 7d3c2b8fdf8..1fa555de994 100644
--- a/doc/development/gitaly.md
+++ b/doc/development/gitaly.md
@@ -277,14 +277,81 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag.
### GitLab Rails
-1. Add feature flag to `lib/gitlab/gitaly_client.rb` (in GitLab Rails):
+1. In GitLab Rails:
- ```ruby
- SERVER_FEATURE_FLAGS = %w[go-find-all-tags].freeze
- ```
+ 1. Add the feature flag to `SERVER_FEATURE_FLAGS` in `lib/feature/gitaly.rb`:
+
+ ```ruby
+ SERVER_FEATURE_FLAGS = %w[go-find-all-tags].freeze
+ ```
+
+ 1. Search for `["gitaly"]["features"]` (currently in `spec/requests/api/internal/base_spec.rb`)
+ and fix the expected results for the tests by adding the new feature flag into it:
+
+ ```ruby
+ expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-get-all-lfs-pointers-go' => 'true', 'gitaly-feature-go-find-all-tags' => 'true')
+ ```
-1. Test in rails console by setting feature flag:
+1. Test in a Rails console by setting the feature flag:
+
+ NOTE: **Note:**
+ Pay attention to the name of the flag and the one used in the Rails console.
+ There is a difference between them (dashes replaced by underscores and name
+ prefix is changed).
```ruby
- Feature.enable('gitaly_go-find-all-tags')
+ Feature.enable('gitaly_go_find_all_tags')
```
+
+### Testing with GDK
+
+To be sure that the flag is set correctly and it goes into Gitaly, you can check
+the integration by using GDK:
+
+1. The state of the flag must be observable. To check it, you need to enable it
+ by fetching the Prometheus metrics:
+ 1. Navigate to GDK's root directory.
+ 1. Make sure you have the proper branch checked out for Gitaly.
+ 1. Recompile it with `make gitaly-setup` and restart the service with `gdk restart gitaly`.
+ 1. Make sure your setup is runnig: `gdk status | grep praefect`.
+ 1. Check what config file is used: `cat ./services/praefect/run | grep praefect` value of the `-config` flag
+ 1. Uncomment `prometheus_listen_addr` in the configuration file and run `gdk restart gitaly`.
+
+1. Make sure that the flag is not enabled yet:
+ 1. Perform whatever action is required to trigger your changes (project creation,
+ submitting commit, observing history, etc.).
+ 1. Check that the list of current metrics has the new counter for the feature flag:
+
+ ```sh
+ curl --silent http://localhost:9236/metrics | grep go_find_all_tags
+ ```
+
+1. Once you observe the metrics for the new feature flag and it increments, you
+ can enable the new feature:
+ 1. Navigate to GDK's root directory.
+ 1. Start a Rails console:
+
+ ```sh
+ bundle install && bundle exec rails console
+ ```
+
+ 1. Check the list of feature flags:
+
+ ```ruby
+ Feature::Gitaly.server_feature_flags
+ ```
+
+ It should be disabled `"gitaly-feature-go-find-all-tags"=>"false"`.
+ 1. Enable it:
+
+ ```ruby
+ Feature.enable('gitaly_go_find_all_tags')
+ ```
+
+ 1. Exit the Rails console and perform whatever action is required to trigger
+ your changes (project creation, submitting commit, observing history, etc.).
+ 1. Verify the feature is on by observing the metrics for it:
+
+ ```sh
+ curl --silent http://localhost:9236/metrics | grep go_find_all_tags
+ ```
diff --git a/doc/public_access/img/project_visibility_confirmation_v12_6.png b/doc/public_access/img/project_visibility_confirmation_v12_6.png
new file mode 100644
index 00000000000..ac4d70ff11a
--- /dev/null
+++ b/doc/public_access/img/project_visibility_confirmation_v12_6.png
Binary files differ
diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md
index bb19436017a..1b6895aaef1 100644
--- a/doc/public_access/public_access.md
+++ b/doc/public_access/public_access.md
@@ -77,6 +77,16 @@ by accident. The restricted visibility settings do not apply to admin users.
For details, see [Restricted visibility levels](../user/admin_area/settings/visibility_and_access_controls.md#restricted-visibility-levels).
+## Reducing visibility
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/33358) in GitLab 12.6.
+
+Reducing a project's visibility level will remove the fork relationship between the project and
+any forked project. This is a potentially destructive action which requires confirmation before
+this can be saved.
+
+![Project visibility change confirmation](img/project_visibility_confirmation_v12_6.png)
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 810bd2a5937..2c7a24da8f9 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -26,6 +26,10 @@ Set up your project's access, [visibility](../../../public_access/public_access.
![projects sharing permissions](img/sharing_and_permissions_settings_v12_3.png)
+CAUTION: **Caution:**
+[Reducing a project's visibility level](../../../public_access/public_access.md#reducing-visibility)
+will remove the fork relationship between the project and any forked project.
+
If Issues are disabled, or you can't access Issues because you're not a project member, then Labels and Milestones
links will be missing from the sidebar UI.
diff --git a/lib/tasks/gitlab/import_export/import.rake b/lib/tasks/gitlab/import_export/import.rake
index d15749d8285..f999a05875d 100644
--- a/lib/tasks/gitlab/import_export/import.rake
+++ b/lib/tasks/gitlab/import_export/import.rake
@@ -17,6 +17,10 @@ namespace :gitlab do
task :import, [:username, :namespace_path, :project_path, :archive_path] => :gitlab_environment do |_t, args|
warn_user_is_not_gitlab
+ if ENV['IMPORT_DEBUG'].present?
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
+ end
+
GitlabProjectImport.new(
namespace_path: args.namespace_path,
project_path: args.project_path,
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 62f1a4c3a14..783766f3406 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -11461,6 +11461,9 @@ msgstr ""
msgid "New branch unavailable"
msgstr ""
+msgid "New changes were added. %{linkStart}Reload the page to review them%{linkEnd}"
+msgstr ""
+
msgid "New deploy key"
msgstr ""
@@ -11989,6 +11992,9 @@ msgstr ""
msgid "Once the exported file is ready, you will receive a notification email with a download link, or you can download it from this page."
msgstr ""
+msgid "Once you confirm and press \"Reduce project visibility\":"
+msgstr ""
+
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -14397,6 +14403,12 @@ msgstr ""
msgid "Redirect to SAML provider to test configuration"
msgstr ""
+msgid "Reduce project visibility"
+msgstr ""
+
+msgid "Reduce this project’s visibility?"
+msgstr ""
+
msgid "Reference:"
msgstr ""
@@ -20401,6 +20413,12 @@ msgstr ""
msgid "You'll need to use different branch names to get a valid comparison."
msgstr ""
+msgid "You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end} in %{strong_start}%{group_name}%{strong_end}."
+msgstr ""
+
+msgid "You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end}."
+msgstr ""
+
msgid "You're not allowed to %{tag_start}edit%{tag_end} files in this project directly. Please fork this project, make your changes there, and submit a merge request."
msgstr ""
diff --git a/package.json b/package.json
index 92675b526f0..c090c6c0359 100644
--- a/package.json
+++ b/package.json
@@ -37,8 +37,8 @@
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-syntax-import-meta": "^7.2.0",
"@babel/preset-env": "^7.6.2",
- "@gitlab/svgs": "^1.82.0",
- "@gitlab/ui": "8.0.1",
+ "@gitlab/svgs": "^1.85.0",
+ "@gitlab/ui": "8.2.0",
"@gitlab/visual-review-tools": "1.2.0",
"@sentry/browser": "^5.7.1",
"@sourcegraph/code-host-integration": "^0.0.14",
@@ -140,7 +140,7 @@
},
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.5.0",
- "@gitlab/eslint-config": "^1.6.0",
+ "@gitlab/eslint-config": "^2.0.0",
"@gitlab/eslint-plugin-i18n": "^1.1.0",
"@gitlab/eslint-plugin-vue-i18n": "^1.2.0",
"@vue/test-utils": "^1.0.0-beta.25",
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index 9e1b4c5c45f..ba7374d5040 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -191,4 +191,28 @@ describe 'Gcp Cluster', :js do
expect(page).not_to have_css('.gcp-signup-offer')
end
end
+
+ context 'when third party offers are disabled' do
+ let(:admin) { create(:admin) }
+ before do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ visit integrations_admin_application_settings_path
+ end
+
+ it 'user does not see the offer' do
+ page.within('.as-third-party-offers') do
+ click_button 'Expand'
+ check 'Do not display offers from third parties within GitLab'
+ click_button 'Save changes'
+ end
+
+ expect(page).to have_content "Application settings saved successfully"
+
+ visit project_clusters_path(project)
+
+ expect(page).not_to have_css('.gcp-signup-offer')
+ end
+ end
end
diff --git a/spec/features/projects/user_changes_project_visibility_spec.rb b/spec/features/projects/user_changes_project_visibility_spec.rb
new file mode 100644
index 00000000000..31da4140d35
--- /dev/null
+++ b/spec/features/projects/user_changes_project_visibility_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'User changes public project visibility', :js do
+ include ProjectForksHelper
+
+ before do
+ fork_project(project, project.owner)
+
+ sign_in(project.owner)
+
+ visit edit_project_path(project)
+ end
+
+ shared_examples 'changing visibility to private' do
+ it 'requires confirmation' do
+ visibility_select = first('.project-feature-controls .select-control')
+ visibility_select.select('Private')
+
+ page.within('#js-shared-permissions') do
+ click_button 'Save changes'
+ end
+
+ find('.js-confirm-danger-input').send_keys(project.path_with_namespace)
+
+ page.within '.modal' do
+ click_button 'Reduce project visibility'
+ end
+
+ expect(page).to have_text("Project '#{project.name}' was successfully updated")
+ end
+ end
+
+ context 'when a project is public' do
+ let(:project) { create(:project, :empty_repo, :public) }
+
+ it_behaves_like 'changing visibility to private'
+ end
+
+ context 'when the project is internal' do
+ let(:project) { create(:project, :empty_repo, :internal) }
+
+ it_behaves_like 'changing visibility to private'
+ end
+end
diff --git a/spec/fixtures/api/schemas/entities/merge_request_poll_cached_widget.json b/spec/fixtures/api/schemas/entities/merge_request_poll_cached_widget.json
index e8959307767..b40b71d2cd6 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_poll_cached_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_poll_cached_widget.json
@@ -26,6 +26,7 @@
"has_conflicts": { "type": "boolean" },
"can_be_merged": { "type": "boolean" },
"remove_source_branch": { "type": ["boolean", "null"] },
+ "diffs_path": { "type": "string" },
"source_branch_exists": { "type": "boolean" },
"branch_missing": { "type": "boolean" },
"commits_without_merge_commits": { "type": "array" },
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
index 2bb2319cc60..3a4fdaf9a20 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
@@ -938,4 +938,31 @@ describe('ReadyToMerge', () => {
expect(customVm.$el.querySelector('.js-modify-commit-message-button')).toBeNull();
});
});
+
+ describe('with a mismatched SHA', () => {
+ const findMismatchShaBlock = () => vm.$el.querySelector('.js-sha-mismatch');
+
+ beforeEach(() => {
+ vm = createComponent({
+ mr: {
+ isSHAMismatch: true,
+ mergeRequestDiffsPath: '/merge_requests/1/diffs',
+ },
+ });
+ });
+
+ it('displays a warning message', () => {
+ expect(findMismatchShaBlock()).toExist();
+ });
+
+ it('warns the user to refresh to review', () => {
+ expect(findMismatchShaBlock().textContent.trim()).toBe(
+ 'New changes were added. Reload the page to review them',
+ );
+ });
+
+ it('displays link to the diffs tab', () => {
+ expect(findMismatchShaBlock().querySelector('a').href).toContain(vm.mr.mergeRequestDiffsPath);
+ });
+ });
});
diff --git a/yarn.lock b/yarn.lock
index c2f8345c0a8..5b6038b6e04 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -690,16 +690,16 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
-"@gitlab/eslint-config@^1.6.0":
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/@gitlab/eslint-config/-/eslint-config-1.6.0.tgz#1fd247d6ab477d53d4c330e05f007e3afa303689"
- integrity sha512-EZffCwsRZmRWPP6N3wp20EJDVGYLG1v43/W7fF/gYQpUjcRclC8ks/jEv8UppasSDlanDmkh1bLWoE9CelSyyw==
+"@gitlab/eslint-config@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/eslint-config/-/eslint-config-2.0.0.tgz#e30dbf2b170a7a4ca003a321de9f4170a2512510"
+ integrity sha512-3Zw3ww8Q4hhVYxO7vliByD0yTeAQn4iBxOyqlASAZepZgdu/OmM4NPbWyntpTfDyHGoRGxmzEaCqv7DS6ubACA==
dependencies:
babel-eslint "^10.0.1"
eslint-config-airbnb-base "^13.1.0"
eslint-config-prettier "^3.3.0"
eslint-plugin-filenames "^1.3.2"
- eslint-plugin-import "^2.16.0"
+ eslint-plugin-import "^2.18.2"
eslint-plugin-promise "^4.1.1"
eslint-plugin-vue "^5.0.0"
@@ -717,15 +717,15 @@
dependencies:
vue-eslint-parser "^6.0.4"
-"@gitlab/svgs@^1.82.0":
- version "1.82.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.82.0.tgz#c059c460afc13ebfe9df370521ca8963fa5afb80"
- integrity sha512-9L4Brys2LCk44lHvFsCFDKN768lYjoMVYDb4PD7FSjqUEruQQ1SRj0rvb1RWKLhiTCDKrtDOXkH6I1TTEms24w==
+"@gitlab/svgs@^1.85.0":
+ version "1.85.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.85.0.tgz#c80247ec4764824385df2837136a0d4a84f881dc"
+ integrity sha512-yzvKut0MPJEbSx/LExopCLpF5KEZsckF+d/Blbji1VqODVanH85oIVuJNmdECUlc7qxye9Or3evpFjW9Pkshmg==
-"@gitlab/ui@8.0.1":
- version "8.0.1"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-8.0.1.tgz#4e3b4791045540785cc389af931e24c6411910ca"
- integrity sha512-PfZPlx3f12wcGxe0eMAXRk1gdhEAkX4czQWAt8EQ1WosKiADCNzCpEPR4jyWa60RF/+zHqJKIjq0VqLMClk8Jg==
+"@gitlab/ui@8.2.0":
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-8.2.0.tgz#82cf512407f8a774878969c72c4227d08ce49aa6"
+ integrity sha512-ZzxA3XwmwZpol6QJjqBf3Oblb1wSFbDJ4QENvPiE9lAUHvhbe8wfKBK++RtgOtd6aXtLvoY1o1Du9qill07Jvg==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"
@@ -4243,7 +4243,7 @@ eslint-plugin-filenames@^1.3.2:
lodash.snakecase "4.1.1"
lodash.upperfirst "4.3.1"
-eslint-plugin-import@^2.16.0, eslint-plugin-import@^2.18.2:
+eslint-plugin-import@^2.18.2:
version "2.18.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz#02f1180b90b077b33d447a17a2326ceb400aceb6"
integrity sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==