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:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-17 21:09:01 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-17 21:09:01 +0300
commite388691e4a5b5b69be903c7eceb606b853719cd5 (patch)
tree97875b98a9a9c7b0dfe9245ce70d5e38ac3a3549
parentcb840235d7fb4001dab266c614bd2cf59036fe18 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--CHANGELOG.md21
-rw-r--r--app/assets/javascripts/boards/index.js8
-rw-r--r--app/assets/javascripts/environments/components/enable_review_app_modal.vue19
-rw-r--r--app/assets/javascripts/environments/index.js1
-rw-r--r--app/assets/javascripts/feature_flags/components/form.vue4
-rw-r--r--app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue2
-rw-r--r--app/assets/javascripts/mr_notes/init_notes.js6
-rw-r--r--app/assets/javascripts/mr_notes/stores/actions.js12
-rw-r--r--app/assets/javascripts/mr_notes/stores/modules/index.js3
-rw-r--r--app/assets/javascripts/mr_notes/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/mr_notes/stores/mutations.js3
-rw-r--r--app/assets/javascripts/pages/admin/users/new/index.js6
-rw-r--r--app/assets/javascripts/pages/projects/jobs/show/index.js2
-rw-r--r--app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue2
-rw-r--r--app/assets/javascripts/repository/components/directory_download_links.vue12
-rw-r--r--app/assets/stylesheets/page_bundles/boards.scss4
-rw-r--r--app/controllers/projects/registry/repositories_controller.rb15
-rw-r--r--app/graphql/resolvers/group_milestones_resolver.rb27
-rw-r--r--app/graphql/types/ci/job_type.rb4
-rw-r--r--app/models/experiment.rb17
-rw-r--r--app/services/issuable_links/create_service.rb4
-rw-r--r--app/views/profiles/accounts/show.html.haml2
-rw-r--r--app/views/profiles/chat_names/new.html.haml2
-rw-r--r--app/views/profiles/emails/index.html.haml2
-rw-r--r--app/views/profiles/gpg_keys/_form.html.haml2
-rw-r--r--app/views/profiles/keys/_form.html.haml4
-rw-r--r--app/views/profiles/passwords/edit.html.haml2
-rw-r--r--app/views/profiles/passwords/new.html.haml2
-rw-r--r--app/views/profiles/show.html.haml4
-rw-r--r--app/views/profiles/two_factor_auths/show.html.haml2
-rw-r--r--app/views/projects/environments/index.html.haml3
-rw-r--r--app/views/projects/merge_requests/creations/_new_compare.html.haml2
-rw-r--r--app/views/projects/merge_requests/show.html.haml5
-rw-r--r--app/views/shared/_file_picker_button.html.haml2
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml5
-rw-r--r--changelogs/unreleased/273283-update-compare-page-button.yml5
-rw-r--r--changelogs/unreleased/323433-add-includeancestors-to-group-milestones-graphql.yml5
-rw-r--r--changelogs/unreleased/324100-monitor.yml5
-rw-r--r--changelogs/unreleased/324649-prevent-experiments-sticking-to-primary.yml5
-rw-r--r--changelogs/unreleased/btn-confirm-download-dir.yml5
-rw-r--r--changelogs/unreleased/btn-confirm-feature-flags.yml5
-rw-r--r--changelogs/unreleased/btn-confirm-user-settings.yml5
-rw-r--r--changelogs/unreleased/jivanvl-add-fields-to-job-type-graphql.yml5
-rw-r--r--changelogs/unreleased/jivanvl-fix-icon-size-pipeline-editor.yml5
-rw-r--r--changelogs/unreleased/kassio-phabricator-enabled-by-default.yml5
-rw-r--r--changelogs/unreleased/mjang-okr-issue300633.yml5
-rw-r--r--changelogs/unreleased/msjr-no-issue-found-for-params.yml5
-rw-r--r--changelogs/unreleased/remove-namespace_project_container_registry_index-json.yml5
-rw-r--r--config/feature_flags/development/phabricator_import.yml2
-rw-r--r--config/initializers/kramdown_patch.rb25
-rw-r--r--db/structure.sql25
-rw-r--r--doc/api/graphql/reference/index.md2
-rw-r--r--doc/integration/vault.md26
-rw-r--r--doc/user/admin_area/credentials_inventory.md18
-rw-r--r--doc/user/application_security/dependency_scanning/index.md47
-rw-r--r--doc/user/group/saml_sso/scim_setup.md8
-rw-r--r--doc/user/project/import/phabricator.md11
-rw-r--r--lib/gitlab/phabricator_import.rb2
-rw-r--r--lib/gitlab/regex.rb4
-rw-r--r--locale/gitlab.pot13
-rw-r--r--spec/controllers/projects/registry/repositories_controller_spec.rb58
-rw-r--r--spec/frontend/environments/enable_review_app_modal_spec.js23
-rw-r--r--spec/frontend/mr_notes/stores/actions_spec.js25
-rw-r--r--spec/frontend/mr_notes/stores/mutations_spec.js15
-rw-r--r--spec/frontend/repository/components/__snapshots__/directory_download_links_spec.js.snap40
-rw-r--r--spec/graphql/resolvers/group_milestones_resolver_spec.rb51
-rw-r--r--spec/graphql/types/ci/job_type_spec.rb2
-rw-r--r--spec/initializers/kramdown_patch_spec.rb38
-rw-r--r--spec/models/experiment_spec.rb29
-rw-r--r--spec/models/merge_request_spec.rb59
-rw-r--r--spec/requests/api/graphql/group/milestones_spec.rb36
-rw-r--r--spec/requests/api/issue_links_spec.rb2
-rw-r--r--spec/requests/projects/issue_links_controller_spec.rb2
-rw-r--r--spec/services/issue_links/create_service_spec.rb6
-rw-r--r--spec/spec_helper.rb4
75 files changed, 640 insertions, 210 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 742a3a2d972..faaf5c97a86 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,13 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 13.9.4 (2021-03-17)
+
+### Security (1 change)
+
+- Patch Kramdown syntax highlighter gem.
+
+
## 13.9.3 (2021-03-08)
### Fixed (4 changes)
@@ -610,6 +617,13 @@ entry.
- Apply new GitLab UI for buttons in pipeline schedules.
+## 13.8.6 (2021-03-17)
+
+### Security (1 change)
+
+- Patch Kramdown syntax highlighter gem.
+
+
## 13.8.5 (2021-03-04)
### Security (6 changes)
@@ -1022,6 +1036,13 @@ entry.
- Add verbiage + link sast to show it's in core. !51935
+## 13.7.9 (2021-03-17)
+
+### Security (1 change)
+
+- Patch Kramdown syntax highlighter gem.
+
+
## 13.7.8 (2021-03-04)
### Security (5 changes)
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index cb22ae3e02c..f0c39d9cf74 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -72,14 +72,6 @@ export default () => {
boardsStore.setTimeTrackingLimitToHours($boardApp.dataset.timeTrackingLimitToHours);
}
- if (gon?.features?.boardsFilteredSearch) {
- import('~/boards/filtered_search')
- .then(({ default: initFilteredSearch }) => {
- initFilteredSearch(apolloProvider);
- })
- .catch(() => {});
- }
-
// eslint-disable-next-line @gitlab/no-runtime-template-compiler
issueBoardsApp = new Vue({
el: $boardApp,
diff --git a/app/assets/javascripts/environments/components/enable_review_app_modal.vue b/app/assets/javascripts/environments/components/enable_review_app_modal.vue
index 2494968857c..b0c0f83b88a 100644
--- a/app/assets/javascripts/environments/components/enable_review_app_modal.vue
+++ b/app/assets/javascripts/environments/components/enable_review_app_modal.vue
@@ -10,6 +10,7 @@ export default {
GlSprintf,
ModalCopyButton,
},
+ inject: ['defaultBranchName'],
props: {
modalId: {
type: String,
@@ -28,7 +29,11 @@ export default {
modalInfo: {
closeText: s__('EnableReviewApp|Close'),
copyToClipboardText: s__('EnableReviewApp|Copy snippet text'),
- copyString: `deploy_review:
+ title: s__('ReviewApp|Enable Review App'),
+ },
+ computed: {
+ modalInfoCopyStr() {
+ return `deploy_review:
stage: deploy
script:
- echo "Deploy a review app"
@@ -38,8 +43,8 @@ export default {
only:
- branches
except:
- - master`,
- title: s__('ReviewApp|Enable Review App'),
+ - ${this.defaultBranchName}`;
+ },
},
};
</script>
@@ -75,7 +80,9 @@ export default {
</gl-sprintf>
</p>
<div class="gl-display-flex align-items-start">
- <pre class="gl-w-full"> {{ $options.modalInfo.copyString }} </pre>
+ <pre class="gl-w-full" data-testid="enable-review-app-copy-string">
+ {{ modalInfoCopyStr }} </pre
+ >
<modal-copy-button
:title="$options.modalInfo.copyToClipboardText"
:text="$options.modalInfo.copyString"
@@ -90,7 +97,9 @@ export default {
<strong>{{ content }}</strong>
</template>
<template #link="{ content }">
- <gl-link href="blob/master/.gitlab-ci.yml" target="_blank">{{ content }}</gl-link>
+ <gl-link :href="`blob/${defaultBranchName}/.gitlab-ci.yml`" target="_blank">{{
+ content
+ }}</gl-link>
</template>
</gl-sprintf>
</p>
diff --git a/app/assets/javascripts/environments/index.js b/app/assets/javascripts/environments/index.js
index 68348648e61..b99872f7a6c 100644
--- a/app/assets/javascripts/environments/index.js
+++ b/app/assets/javascripts/environments/index.js
@@ -22,6 +22,7 @@ export default () => {
apolloProvider,
provide: {
projectPath: el.dataset.projectPath,
+ defaultBranchName: el.dataset.defaultBranchName,
},
data() {
const environmentsData = el.dataset;
diff --git a/app/assets/javascripts/feature_flags/components/form.vue b/app/assets/javascripts/feature_flags/components/form.vue
index f6a14d9996f..1f59b709aa2 100644
--- a/app/assets/javascripts/feature_flags/components/form.vue
+++ b/app/assets/javascripts/feature_flags/components/form.vue
@@ -314,7 +314,7 @@ export default {
<h4>{{ s__('FeatureFlags|Strategies') }}</h4>
<div class="flex align-items-baseline justify-content-between">
<p class="mr-3">{{ $options.translations.newHelpText }}</p>
- <gl-button variant="success" category="secondary" @click="addStrategy">
+ <gl-button variant="confirm" category="secondary" @click="addStrategy">
{{ s__('FeatureFlags|Add strategy') }}
</gl-button>
</div>
@@ -575,7 +575,7 @@ export default {
ref="submitButton"
:disabled="readOnly"
type="button"
- variant="success"
+ variant="confirm"
class="js-ff-submit col-xs-12"
@click="handleSubmit"
>{{ submitText }}</gl-button
diff --git a/app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue b/app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue
index 627af202028..1765a2f3d5d 100644
--- a/app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue
+++ b/app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue
@@ -23,7 +23,7 @@ export default {
},
},
radioVals: {
- /* Use the default branch (e.g. master) */
+ /* Use the default branch (e.g. main) */
DEFAULT: 'DEFAULT',
/* Create a new branch */
NEW: 'NEW',
diff --git a/app/assets/javascripts/mr_notes/init_notes.js b/app/assets/javascripts/mr_notes/init_notes.js
index 9a93e90c2bb..ff194d1a171 100644
--- a/app/assets/javascripts/mr_notes/init_notes.js
+++ b/app/assets/javascripts/mr_notes/init_notes.js
@@ -25,6 +25,9 @@ export default () => {
return {
noteableData,
+ endpoints: {
+ metadata: notesDataset.endpointMetadata,
+ },
currentUserData: JSON.parse(notesDataset.currentUserData),
notesData: JSON.parse(notesDataset.notesData),
helpPagePath: notesDataset.helpPagePath,
@@ -54,6 +57,7 @@ export default () => {
},
created() {
this.setActiveTab(window.mrTabs.getCurrentAction());
+ this.setEndpoints(this.endpoints);
},
mounted() {
this.notesCountBadge = $('.issuable-details').find('.notes-tab .badge');
@@ -65,7 +69,7 @@ export default () => {
window.mrTabs.eventHub.$off('MergeRequestTabChange', this.setActiveTab);
},
methods: {
- ...mapActions(['setActiveTab']),
+ ...mapActions(['setActiveTab', 'setEndpoints']),
updateDiscussionTabCounter() {
this.notesCountBadge.text(this.discussionTabCounter);
},
diff --git a/app/assets/javascripts/mr_notes/stores/actions.js b/app/assets/javascripts/mr_notes/stores/actions.js
index 426c6a00d5e..d1874dcb214 100644
--- a/app/assets/javascripts/mr_notes/stores/actions.js
+++ b/app/assets/javascripts/mr_notes/stores/actions.js
@@ -1,7 +1,9 @@
import types from './mutation_types';
-export default {
- setActiveTab({ commit }, tab) {
- commit(types.SET_ACTIVE_TAB, tab);
- },
-};
+export function setActiveTab({ commit }, tab) {
+ commit(types.SET_ACTIVE_TAB, tab);
+}
+
+export function setEndpoints({ commit }, endpoints) {
+ commit(types.SET_ENDPOINTS, endpoints);
+}
diff --git a/app/assets/javascripts/mr_notes/stores/modules/index.js b/app/assets/javascripts/mr_notes/stores/modules/index.js
index c28e666943b..6e228c62a72 100644
--- a/app/assets/javascripts/mr_notes/stores/modules/index.js
+++ b/app/assets/javascripts/mr_notes/stores/modules/index.js
@@ -1,9 +1,10 @@
-import actions from '../actions';
+import * as actions from '../actions';
import getters from '../getters';
import mutations from '../mutations';
export default () => ({
state: {
+ endpoints: {},
activeTab: null,
},
actions,
diff --git a/app/assets/javascripts/mr_notes/stores/mutation_types.js b/app/assets/javascripts/mr_notes/stores/mutation_types.js
index 105104361cf..67fa63f882d 100644
--- a/app/assets/javascripts/mr_notes/stores/mutation_types.js
+++ b/app/assets/javascripts/mr_notes/stores/mutation_types.js
@@ -1,3 +1,4 @@
export default {
SET_ACTIVE_TAB: 'SET_ACTIVE_TAB',
+ SET_ENDPOINTS: 'SET_ENDPOINTS',
};
diff --git a/app/assets/javascripts/mr_notes/stores/mutations.js b/app/assets/javascripts/mr_notes/stores/mutations.js
index 8175aa9488f..3843103f4d0 100644
--- a/app/assets/javascripts/mr_notes/stores/mutations.js
+++ b/app/assets/javascripts/mr_notes/stores/mutations.js
@@ -4,4 +4,7 @@ export default {
[types.SET_ACTIVE_TAB](state, tab) {
Object.assign(state, { activeTab: tab });
},
+ [types.SET_ENDPOINTS](state, endpoints) {
+ Object.assign(state, { endpoints });
+ },
};
diff --git a/app/assets/javascripts/pages/admin/users/new/index.js b/app/assets/javascripts/pages/admin/users/new/index.js
index 7b7d4c169ef..01710246c86 100644
--- a/app/assets/javascripts/pages/admin/users/new/index.js
+++ b/app/assets/javascripts/pages/admin/users/new/index.js
@@ -45,7 +45,5 @@ export default class UserInternalRegexHandler {
}
}
-document.addEventListener('DOMContentLoaded', () => {
- // eslint-disable-next-line
- new UserInternalRegexHandler();
-});
+// eslint-disable-next-line no-new
+new UserInternalRegexHandler();
diff --git a/app/assets/javascripts/pages/projects/jobs/show/index.js b/app/assets/javascripts/pages/projects/jobs/show/index.js
index d57dbeb1242..6fef057dee0 100644
--- a/app/assets/javascripts/pages/projects/jobs/show/index.js
+++ b/app/assets/javascripts/pages/projects/jobs/show/index.js
@@ -1,3 +1,3 @@
import initJobDetails from '~/jobs';
-document.addEventListener('DOMContentLoaded', initJobDetails);
+initJobDetails();
diff --git a/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue b/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue
index f36b22f33c3..459580c86d6 100644
--- a/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue
+++ b/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue
@@ -82,7 +82,7 @@ export default {
</gl-alert>
<div v-else>
<div class="gl-display-flex gl-align-items-center">
- <gl-icon :size="18" name="lock" use-deprecated-sizes class="gl-text-gray-500 gl-mr-3" />
+ <gl-icon :size="16" name="lock" class="gl-text-gray-500 gl-mr-3" />
{{ $options.i18n.viewOnlyMessage }}
</div>
<div class="gl-mt-3 gl-border-solid gl-border-gray-100 gl-border-1">
diff --git a/app/assets/javascripts/repository/components/directory_download_links.vue b/app/assets/javascripts/repository/components/directory_download_links.vue
index 8c029fc9973..c222a83300d 100644
--- a/app/assets/javascripts/repository/components/directory_download_links.vue
+++ b/app/assets/javascripts/repository/components/directory_download_links.vue
@@ -1,9 +1,9 @@
<script>
-import { GlLink } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
export default {
components: {
- GlLink,
+ GlButton,
},
props: {
currentPath: {
@@ -32,15 +32,15 @@ export default {
<h5 class="m-0 dropdown-bold-header">{{ __('Download this directory') }}</h5>
<div class="dropdown-menu-content">
<div class="btn-group ml-0 w-100">
- <gl-link
+ <gl-button
v-for="(link, index) in normalizedLinks"
:key="index"
:href="link.path"
- :class="{ 'btn-primary': index === 0 }"
- class="btn btn-xs"
+ :variant="index === 0 ? 'confirm' : 'default'"
+ size="small"
>
{{ link.text }}
- </gl-link>
+ </gl-button>
</div>
</div>
</section>
diff --git a/app/assets/stylesheets/page_bundles/boards.scss b/app/assets/stylesheets/page_bundles/boards.scss
index fdf9e157e1e..61cbfec4597 100644
--- a/app/assets/stylesheets/page_bundles/boards.scss
+++ b/app/assets/stylesheets/page_bundles/boards.scss
@@ -40,8 +40,8 @@
[data-page$='epic_boards:index'],
[data-page$='epic_boards:show'] {
- .filter-form {
- display: none;
+ .filtered-search-wrapper {
+ display: none !important;
}
}
diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb
index 28a86ecc9f0..8acebd89033 100644
--- a/app/controllers/projects/registry/repositories_controller.rb
+++ b/app/controllers/projects/registry/repositories_controller.rb
@@ -6,22 +6,11 @@ module Projects
include PackagesHelper
before_action :authorize_update_container_image!, only: [:destroy]
- before_action :ensure_root_container_repository!, only: [:index]
def index
respond_to do |format|
- format.html
- format.json do
- @images = ContainerRepositoriesFinder.new(user: current_user, subject: project, params: params.slice(:name))
- .execute
-
- track_package_event(:list_repositories, :container)
-
- serializer = ContainerRepositoriesSerializer
- .new(project: project, current_user: current_user)
-
- render json: serializer.with_pagination(request, response).represent(@images)
- end
+ format.html { ensure_root_container_repository! }
+ format.json { render_404 }
end
end
diff --git a/app/graphql/resolvers/group_milestones_resolver.rb b/app/graphql/resolvers/group_milestones_resolver.rb
index 179283fd7b7..640c320dcfa 100644
--- a/app/graphql/resolvers/group_milestones_resolver.rb
+++ b/app/graphql/resolvers/group_milestones_resolver.rb
@@ -5,18 +5,37 @@ module Resolvers
class GroupMilestonesResolver < MilestonesResolver
argument :include_descendants, GraphQL::BOOLEAN_TYPE,
required: false,
- description: 'Also return milestones in all subgroups and subprojects.'
+ description: 'Include milestones from all subgroups and subprojects.'
+ argument :include_ancestors, GraphQL::BOOLEAN_TYPE,
+ required: false,
+ description: 'Include milestones from all parent groups.'
type Types::MilestoneType.connection_type, null: true
private
def parent_id_parameters(args)
- return { group_ids: parent.id } unless args[:include_descendants].present?
+ include_ancestors = args[:include_ancestors].present?
+ include_descendants = args[:include_descendants].present?
+ return { group_ids: parent.id } unless include_ancestors || include_descendants
+
+ group_ids = if include_ancestors && include_descendants
+ parent.self_and_hierarchy
+ elsif include_ancestors
+ parent.self_and_ancestors
+ else
+ parent.self_and_descendants
+ end
+
+ project_ids = if include_descendants
+ group_projects.with_issues_or_mrs_available_for_user(current_user)
+ else
+ nil
+ end
{
- group_ids: parent.self_and_descendants.public_or_visible_to_user(current_user).select(:id),
- project_ids: group_projects.with_issues_or_mrs_available_for_user(current_user)
+ group_ids: group_ids.public_or_visible_to_user(current_user).select(:id),
+ project_ids: project_ids
}
end
diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb
index c86337eea89..f2529b8e5c8 100644
--- a/app/graphql/types/ci/job_type.rb
+++ b/app/graphql/types/ci/job_type.rb
@@ -6,6 +6,8 @@ module Types
graphql_name 'CiJob'
authorize :read_commit_status
+ field :id, GraphQL::ID_TYPE, null: false,
+ description: 'ID of the job.'
field :pipeline, Types::Ci::PipelineType, null: true,
description: 'Pipeline the job belongs to.'
field :name, GraphQL::STRING_TYPE, null: true,
@@ -22,6 +24,8 @@ module Types
description: 'When a job has finished running.'
field :duration, GraphQL::INT_TYPE, null: true,
description: 'Duration of the job in seconds.'
+ field :short_sha, type: GraphQL::STRING_TYPE, null: false,
+ description: 'Short SHA1 ID of the commit.'
def pipeline
Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Pipeline, object.pipeline_id).find
diff --git a/app/models/experiment.rb b/app/models/experiment.rb
index ac8b6516d02..7ffb321f2b7 100644
--- a/app/models/experiment.rb
+++ b/app/models/experiment.rb
@@ -21,7 +21,13 @@ class Experiment < ApplicationRecord
# Create or update the recorded experiment_user row for the user in this experiment.
def record_user_and_group(user, group_type, context = {})
experiment_user = experiment_users.find_or_initialize_by(user: user)
- experiment_user.update!(group_type: group_type, context: merged_context(experiment_user, context))
+ experiment_user.assign_attributes(group_type: group_type, context: merged_context(experiment_user, context))
+ # We only call save when necessary because this causes the request to stick to the primary DB
+ # even when the save is a no-op
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/324649
+ experiment_user.save! if experiment_user.changed?
+
+ experiment_user
end
def record_conversion_event_for_user(user, context = {})
@@ -32,7 +38,14 @@ class Experiment < ApplicationRecord
end
def record_group_and_variant!(group, variant)
- experiment_subjects.find_or_initialize_by(group: group).update!(variant: variant)
+ experiment_subject = experiment_subjects.find_or_initialize_by(group: group)
+ experiment_subject.assign_attributes(variant: variant)
+ # We only call save when necessary because this causes the request to stick to the primary DB
+ # even when the save is a no-op
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/324649
+ experiment_subject.save! if experiment_subject.changed?
+
+ experiment_subject
end
private
diff --git a/app/services/issuable_links/create_service.rb b/app/services/issuable_links/create_service.rb
index f148c503dcf..4816be566dd 100644
--- a/app/services/issuable_links/create_service.rb
+++ b/app/services/issuable_links/create_service.rb
@@ -107,11 +107,11 @@ module IssuableLinks
end
def issuables_assigned_message
- 'Issue(s) already assigned'
+ _("Issue(s) already assigned")
end
def issuables_not_found_message
- 'No Issue found for given params'
+ _("No matching issue found. Make sure that you are adding a valid issue URL.")
end
end
end
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index 1f09f3097ad..82bd5c095a8 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -28,7 +28,7 @@
= link_to _('Manage two-factor authentication'), profile_two_factor_auth_path, class: 'gl-button btn btn-confirm'
- else
.gl-mb-3
- = link_to _('Enable two-factor authentication'), profile_two_factor_auth_path, class: 'gl-button btn btn-success', data: { qa_selector: 'enable_2fa_button' }
+ = link_to _('Enable two-factor authentication'), profile_two_factor_auth_path, class: 'gl-button btn btn-confirm', data: { qa_selector: 'enable_2fa_button' }
.col-lg-12
%hr
diff --git a/app/views/profiles/chat_names/new.html.haml b/app/views/profiles/chat_names/new.html.haml
index 4651854a551..f008abf376d 100644
--- a/app/views/profiles/chat_names/new.html.haml
+++ b/app/views/profiles/chat_names/new.html.haml
@@ -8,7 +8,7 @@
.actions
= form_tag profile_chat_names_path, method: :post do
= hidden_field_tag :token, @chat_name_token.token
- = submit_tag _("Authorize"), class: "gl-button btn btn-success wide float-left"
+ = submit_tag _("Authorize"), class: "gl-button btn btn-confirm wide float-left"
= form_tag deny_profile_chat_names_path, method: :delete do
= hidden_field_tag :token, @chat_name_token.token
= submit_tag _("Deny"), class: "gl-button btn btn-danger gl-ml-3"
diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml
index 89198b0a65b..d78b542ae8a 100644
--- a/app/views/profiles/emails/index.html.haml
+++ b/app/views/profiles/emails/index.html.haml
@@ -15,7 +15,7 @@
= f.label :email, _('Email'), class: 'label-bold'
= f.text_field :email, class: 'form-control gl-form-input', data: { qa_selector: 'email_address_field' }
.gl-mt-3
- = f.submit _('Add email address'), class: 'gl-button btn btn-success', data: { qa_selector: 'add_email_address_button' }
+ = f.submit _('Add email address'), class: 'gl-button btn btn-confirm', data: { qa_selector: 'add_email_address_button' }
%hr
%h4.gl-mt-0
= _('Linked emails (%{email_count})') % { email_count: @emails.load.size + 1 }
diff --git a/app/views/profiles/gpg_keys/_form.html.haml b/app/views/profiles/gpg_keys/_form.html.haml
index 7a7b5802cd8..a86de0681f7 100644
--- a/app/views/profiles/gpg_keys/_form.html.haml
+++ b/app/views/profiles/gpg_keys/_form.html.haml
@@ -7,4 +7,4 @@
= f.text_area :key, class: "form-control", rows: 8, required: true, placeholder: _("Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'.")
.gl-mt-3
- = f.submit s_('Profiles|Add key'), class: "gl-button btn btn-success"
+ = f.submit s_('Profiles|Add key'), class: "gl-button btn btn-confirm"
diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml
index 81a543de7a3..96a05097935 100644
--- a/app/views/profiles/keys/_form.html.haml
+++ b/app/views/profiles/keys/_form.html.haml
@@ -21,7 +21,7 @@
%strong= _('Oops, are you sure?')
%p= s_("Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible.")
- %button.btn.gl-button.btn-success.js-add-ssh-key-validation-confirm-submit= _("Yes, add it")
+ %button.btn.gl-button.btn-confirm.js-add-ssh-key-validation-confirm-submit= _("Yes, add it")
.gl-mt-3
- = f.submit s_('Profiles|Add key'), class: "gl-button btn btn-success js-add-ssh-key-validation-original-submit qa-add-key-button"
+ = f.submit s_('Profiles|Add key'), class: "gl-button btn btn-confirm js-add-ssh-key-validation-original-submit qa-add-key-button"
diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml
index b281dbb4367..2cc919fc70e 100644
--- a/app/views/profiles/passwords/edit.html.haml
+++ b/app/views/profiles/passwords/edit.html.haml
@@ -30,6 +30,6 @@
= f.label :password_confirmation, _('Password confirmation'), class: 'label-bold'
= f.password_field :password_confirmation, required: true, class: 'form-control gl-form-input', data: { qa_selector: 'confirm_password_field' }
.gl-mt-3.gl-mb-3
- = f.submit _('Save password'), class: "gl-button btn btn-success gl-mr-3", data: { qa_selector: 'save_password_button' }
+ = f.submit _('Save password'), class: "gl-button btn btn-confirm gl-mr-3", data: { qa_selector: 'save_password_button' }
- unless @user.password_automatically_set?
= link_to _('I forgot my password'), reset_profile_password_path, method: :put
diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml
index ffec6baa20e..efcd0bb621f 100644
--- a/app/views/profiles/passwords/new.html.haml
+++ b/app/views/profiles/passwords/new.html.haml
@@ -28,4 +28,4 @@
.col-sm-10
= f.password_field :password_confirmation, required: true, class: 'form-control gl-form-input'
.form-actions
- = f.submit _('Set new password'), class: 'gl-button btn btn-success'
+ = f.submit _('Set new password'), class: 'gl-button btn btn-confirm'
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 7995231c739..cc5ce00669e 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -33,7 +33,7 @@
%h5.gl-mt-0= s_("Profiles|Upload new avatar")
.gl-mt-2.gl-mb-3
%button.gl-button.btn.js-choose-user-avatar-button{ type: 'button' }= s_("Profiles|Choose file...")
- %span.avatar-file-name.gl-ml-3.js-avatar-filename= s_("Profiles|No file chosen")
+ %span.avatar-file-name.gl-ml-3.js-avatar-filename= s_("Profiles|No file chosen.")
= f.file_field_without_bootstrap :avatar, class: 'js-user-avatar-input hidden', accept: 'image/*'
.form-text.text-muted= s_("Profiles|The maximum file size allowed is 200KB.")
- if @user.avatar?
@@ -127,7 +127,7 @@
= s_("Profiles|Choose to show contributions of private projects on your public profile without any project, repository or organization information")
.row.gl-mt-3.gl-mb-3.gl-justify-content-end
.col-lg-8
- = f.submit s_("Profiles|Update profile settings"), class: 'gl-button btn btn-success'
+ = f.submit s_("Profiles|Update profile settings"), class: 'gl-button btn btn-confirm'
= link_to _("Cancel"), user_path(current_user), class: 'gl-button btn btn-cancel'
.modal.modal-profile-crop{ data: { cropper_css_path: ActionController::Base.helpers.stylesheet_path('lazy_bundles/cropper.css') } }
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index 3853f428447..a9134057777 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -51,7 +51,7 @@
= label_tag :pin_code, _('Pin code'), class: "label-bold"
= text_field_tag :pin_code, nil, class: "form-control", required: true, data: { qa_selector: 'pin_code_field' }
.gl-mt-3
- = submit_tag _('Register with two-factor app'), class: 'gl-button btn btn-success', data: { qa_selector: 'register_2fa_app_button' }
+ = submit_tag _('Register with two-factor app'), class: 'gl-button btn btn-confirm', data: { qa_selector: 'register_2fa_app_button' }
%hr
diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml
index 5da9c25b780..06a2ed46805 100644
--- a/app/views/projects/environments/index.html.haml
+++ b/app/views/projects/environments/index.html.haml
@@ -6,4 +6,5 @@
"can-create-environment" => can?(current_user, :create_environment, @project).to_s,
"new-environment-path" => new_project_environment_path(@project),
"help-page-path" => help_page_path("ci/environments/index.md"),
- "project-path" => @project.full_path } }
+ "project-path" => @project.full_path,
+ "default-branch-name" => @project.default_branch_or_master } }
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 2cb75d43d4b..c7861f4a01a 100644
--- a/app/views/projects/merge_requests/creations/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_compare.html.haml
@@ -64,4 +64,4 @@
- if @merge_request.errors.any?
= form_errors(@merge_request)
- = f.submit 'Compare branches and continue', class: "gl-button btn btn-success mr-compare-btn"
+ = f.submit 'Compare branches and continue', class: "gl-button btn btn-confirm mr-compare-btn"
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index f0dcaf24e07..36491b0d8b8 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -13,6 +13,8 @@
- add_page_specific_style 'page_bundles/reports'
- add_page_specific_style 'page_bundles/ci_status'
+- add_page_startup_api_call @endpoint_metadata_url
+
.merge-request{ data: { mr_action: mr_action, url: merge_request_path(@merge_request, format: :json), project_path: project_path(@merge_request.project), lock_version: @merge_request.lock_version } }
= render "projects/merge_requests/mr_title"
@@ -63,6 +65,7 @@
- add_page_startup_api_call widget_project_json_merge_request_path(@project, @merge_request, format: :json)
- add_page_startup_api_call cached_widget_project_json_merge_request_path(@project, @merge_request, format: :json)
#js-vue-mr-discussions{ data: { notes_data: notes_data(@merge_request, Feature.enabled?(:paginated_notes, @project)).to_json,
+ endpoint_metadata: @endpoint_metadata_url,
noteable_data: serialize_issuable(@merge_request, serializer: 'noteable'),
noteable_type: 'MergeRequest',
target_type: 'merge_request',
@@ -75,8 +78,6 @@
= render "projects/merge_requests/tabs/pane", name: "pipelines", id: "pipelines", class: "pipelines" do
- if number_of_pipelines.nonzero?
= render 'projects/commit/pipelines_list', disable_initialization: true, endpoint: pipelines_project_merge_request_path(@project, @merge_request)
- - if mr_action === "diffs"
- - add_page_startup_api_call @endpoint_metadata_url
- params = request.query_parameters
- if Feature.enabled?(:default_merge_ref_for_diffs, @project, default_enabled: :yaml)
- params = params.merge(diff_head: true)
diff --git a/app/views/shared/_file_picker_button.html.haml b/app/views/shared/_file_picker_button.html.haml
index 9e6a7626d89..a30c144c38f 100644
--- a/app/views/shared/_file_picker_button.html.haml
+++ b/app/views/shared/_file_picker_button.html.haml
@@ -2,7 +2,7 @@
%span.js-filepicker
%button.gl-button.btn.js-filepicker-button{ type: 'button', class: classes }= _("Choose file…")
- %span.file_name.js-filepicker-filename= _("No file chosen")
+ %span.file_name.js-filepicker-filename= _("No file chosen.")
= f.file_field field, class: "js-filepicker-input hidden"
- if help_text.present?
.form-text.text-muted= help_text
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index f5b2868aa6c..4233dfec698 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -5,7 +5,8 @@
- placeholder = local_assigns[:placeholder] || _('Search or filter results...')
- is_not_boards_modal_or_productivity_analytics = type != :boards_modal && type != :productivity_analytics
- block_css_class = is_not_boards_modal_or_productivity_analytics ? 'row-content-block second-block' : ''
-- if board && board.to_type == "EpicBoard"
+- is_epic_board = board&.to_type == "EpicBoard"
+- if is_epic_board
- user_can_admin_list = can?(current_user, :admin_epic_board_list, board.resource_parent)
- elsif board
- user_can_admin_list = can?(current_user, :admin_issue_board_list, board.resource_parent)
@@ -21,7 +22,7 @@
- if @can_bulk_update
.check-all-holder.d-none.d-sm-block.hidden
= check_box_tag "check-all-issues", nil, false, class: "check-all-issues left"
- - if Feature.enabled?(:boards_filtered_search, @group)
+ - if Feature.enabled?(:boards_filtered_search, @group) && is_epic_board
#js-board-filtered-search
- else
.issues-other-filters.filtered-search-wrapper.d-flex.flex-column.flex-md-row
diff --git a/changelogs/unreleased/273283-update-compare-page-button.yml b/changelogs/unreleased/273283-update-compare-page-button.yml
new file mode 100644
index 00000000000..37e48e386fe
--- /dev/null
+++ b/changelogs/unreleased/273283-update-compare-page-button.yml
@@ -0,0 +1,5 @@
+---
+title: Update compare branches button to btn-confirm
+merge_request: 56791
+author:
+type: changed
diff --git a/changelogs/unreleased/323433-add-includeancestors-to-group-milestones-graphql.yml b/changelogs/unreleased/323433-add-includeancestors-to-group-milestones-graphql.yml
new file mode 100644
index 00000000000..56cd6538bc6
--- /dev/null
+++ b/changelogs/unreleased/323433-add-includeancestors-to-group-milestones-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Support include_ancestors when querying group milestones via GraphQL
+merge_request: 56667
+author:
+type: added
diff --git a/changelogs/unreleased/324100-monitor.yml b/changelogs/unreleased/324100-monitor.yml
new file mode 100644
index 00000000000..90929823825
--- /dev/null
+++ b/changelogs/unreleased/324100-monitor.yml
@@ -0,0 +1,5 @@
+---
+title: Update master to main inside monitor copy
+merge_request: 56264
+author:
+type: changed
diff --git a/changelogs/unreleased/324649-prevent-experiments-sticking-to-primary.yml b/changelogs/unreleased/324649-prevent-experiments-sticking-to-primary.yml
new file mode 100644
index 00000000000..4657e2f0a81
--- /dev/null
+++ b/changelogs/unreleased/324649-prevent-experiments-sticking-to-primary.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent sticking to DB primary when experiments are tracked
+merge_request: 56852
+author:
+type: performance
diff --git a/changelogs/unreleased/btn-confirm-download-dir.yml b/changelogs/unreleased/btn-confirm-download-dir.yml
new file mode 100644
index 00000000000..5d438939d17
--- /dev/null
+++ b/changelogs/unreleased/btn-confirm-download-dir.yml
@@ -0,0 +1,5 @@
+---
+title: Move to btn-confirm in download directory dropdown
+merge_request: 56193
+author: Yogi (@yo)
+type: changed
diff --git a/changelogs/unreleased/btn-confirm-feature-flags.yml b/changelogs/unreleased/btn-confirm-feature-flags.yml
new file mode 100644
index 00000000000..999c042845b
--- /dev/null
+++ b/changelogs/unreleased/btn-confirm-feature-flags.yml
@@ -0,0 +1,5 @@
+---
+title: Move to confirm variant from success in feature_flags directory
+merge_request: 56202
+author: Yogi (@yo)
+type: changed
diff --git a/changelogs/unreleased/btn-confirm-user-settings.yml b/changelogs/unreleased/btn-confirm-user-settings.yml
new file mode 100644
index 00000000000..2762b2db139
--- /dev/null
+++ b/changelogs/unreleased/btn-confirm-user-settings.yml
@@ -0,0 +1,5 @@
+---
+title: Move from btn-success to btn-confirm in app/views/profiles directory
+merge_request: 54748
+author: Yogi (@yo)
+type: changed
diff --git a/changelogs/unreleased/jivanvl-add-fields-to-job-type-graphql.yml b/changelogs/unreleased/jivanvl-add-fields-to-job-type-graphql.yml
new file mode 100644
index 00000000000..35d5b737b6b
--- /dev/null
+++ b/changelogs/unreleased/jivanvl-add-fields-to-job-type-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Add id and short_sha GraphQL fields to jobType in the CI namespace
+merge_request: 56714
+author:
+type: changed
diff --git a/changelogs/unreleased/jivanvl-fix-icon-size-pipeline-editor.yml b/changelogs/unreleased/jivanvl-fix-icon-size-pipeline-editor.yml
new file mode 100644
index 00000000000..211a95643b0
--- /dev/null
+++ b/changelogs/unreleased/jivanvl-fix-icon-size-pipeline-editor.yml
@@ -0,0 +1,5 @@
+---
+title: Change icon size in the pipeline editor
+merge_request: 56780
+author:
+type: changed
diff --git a/changelogs/unreleased/kassio-phabricator-enabled-by-default.yml b/changelogs/unreleased/kassio-phabricator-enabled-by-default.yml
new file mode 100644
index 00000000000..0a4234f8987
--- /dev/null
+++ b/changelogs/unreleased/kassio-phabricator-enabled-by-default.yml
@@ -0,0 +1,5 @@
+---
+title: Enabled phabricator importer by default
+merge_request: 56765
+author:
+type: added
diff --git a/changelogs/unreleased/mjang-okr-issue300633.yml b/changelogs/unreleased/mjang-okr-issue300633.yml
new file mode 100644
index 00000000000..f73a8e0a7ac
--- /dev/null
+++ b/changelogs/unreleased/mjang-okr-issue300633.yml
@@ -0,0 +1,5 @@
+---
+title: Update UI text to match style guidelines
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/msjr-no-issue-found-for-params.yml b/changelogs/unreleased/msjr-no-issue-found-for-params.yml
new file mode 100644
index 00000000000..df314f51411
--- /dev/null
+++ b/changelogs/unreleased/msjr-no-issue-found-for-params.yml
@@ -0,0 +1,5 @@
+---
+title: Resolve Improve text for error No issue found for given params in UI
+merge_request: 45064
+author:
+type: other
diff --git a/changelogs/unreleased/remove-namespace_project_container_registry_index-json.yml b/changelogs/unreleased/remove-namespace_project_container_registry_index-json.yml
new file mode 100644
index 00000000000..54cfd8a902f
--- /dev/null
+++ b/changelogs/unreleased/remove-namespace_project_container_registry_index-json.yml
@@ -0,0 +1,5 @@
+---
+title: Remove JSON endpoint for project container index
+merge_request: 52407
+author: Takuya Noguchi
+type: other
diff --git a/config/feature_flags/development/phabricator_import.yml b/config/feature_flags/development/phabricator_import.yml
index 264988e8006..5340caef140 100644
--- a/config/feature_flags/development/phabricator_import.yml
+++ b/config/feature_flags/development/phabricator_import.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/1197
milestone: '12.0'
type: development
group: group::import
-default_enabled: false
+default_enabled: true
diff --git a/config/initializers/kramdown_patch.rb b/config/initializers/kramdown_patch.rb
new file mode 100644
index 00000000000..5cb769cec24
--- /dev/null
+++ b/config/initializers/kramdown_patch.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+#
+# This pulls in https://github.com/gettalong/kramdown/pull/708 for kramdown v2.3.0.
+# Remove this file when that pull request is merged and released.
+require 'kramdown/converter'
+require 'kramdown/converter/syntax_highlighter/rouge'
+
+module Kramdown::Converter::SyntaxHighlighter
+ module Rouge
+ def self.formatter_class(opts = {})
+ case formatter = opts[:formatter]
+ when Class
+ formatter
+ when /\A[[:upper:]][[:alnum:]_]*\z/
+ ::Rouge::Formatters.const_get(formatter, false)
+ else
+ # Available in Rouge 2.0 or later
+ ::Rouge::Formatters::HTMLLegacy
+ end
+ rescue NameError
+ # Fallback to Rouge 1.x
+ ::Rouge::Formatters::HTML
+ end
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index 29c3e973f4c..0c4bd0d4ff6 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -9432,39 +9432,39 @@ CREATE TABLE application_settings (
elasticsearch_indexed_file_size_limit_kb integer DEFAULT 1024 NOT NULL,
enforce_namespace_storage_limit boolean DEFAULT false NOT NULL,
container_registry_delete_tags_service_timeout integer DEFAULT 250 NOT NULL,
- kroki_url character varying,
- kroki_enabled boolean,
- elasticsearch_client_request_timeout integer DEFAULT 0 NOT NULL,
gitpod_enabled boolean DEFAULT false NOT NULL,
gitpod_url text DEFAULT 'https://gitpod.io/'::text,
+ elasticsearch_client_request_timeout integer DEFAULT 0 NOT NULL,
abuse_notification_email character varying,
require_admin_approval_after_user_signup boolean DEFAULT true NOT NULL,
help_page_documentation_base_url text,
automatic_purchased_storage_allocation boolean DEFAULT false NOT NULL,
+ container_registry_expiration_policies_worker_capacity integer DEFAULT 0 NOT NULL,
encrypted_ci_jwt_signing_key text,
encrypted_ci_jwt_signing_key_iv text,
- container_registry_expiration_policies_worker_capacity integer DEFAULT 0 NOT NULL,
- elasticsearch_analyzers_smartcn_enabled boolean DEFAULT false NOT NULL,
- elasticsearch_analyzers_smartcn_search boolean DEFAULT false NOT NULL,
- elasticsearch_analyzers_kuromoji_enabled boolean DEFAULT false NOT NULL,
- elasticsearch_analyzers_kuromoji_search boolean DEFAULT false NOT NULL,
secret_detection_token_revocation_enabled boolean DEFAULT false NOT NULL,
secret_detection_token_revocation_url text,
encrypted_secret_detection_token_revocation_token text,
encrypted_secret_detection_token_revocation_token_iv text,
+ elasticsearch_analyzers_smartcn_enabled boolean DEFAULT false NOT NULL,
+ elasticsearch_analyzers_smartcn_search boolean DEFAULT false NOT NULL,
+ elasticsearch_analyzers_kuromoji_enabled boolean DEFAULT false NOT NULL,
+ elasticsearch_analyzers_kuromoji_search boolean DEFAULT false NOT NULL,
+ new_user_signups_cap integer,
domain_denylist_enabled boolean DEFAULT false,
domain_denylist text,
domain_allowlist text,
- new_user_signups_cap integer,
encrypted_cloud_license_auth_token text,
encrypted_cloud_license_auth_token_iv text,
secret_detection_revocation_token_types_url text,
cloud_license_enabled boolean DEFAULT false NOT NULL,
+ kroki_url text,
+ kroki_enabled boolean DEFAULT false NOT NULL,
disable_feed_token boolean DEFAULT false NOT NULL,
personal_access_token_prefix text,
rate_limiting_response_text text,
- invisible_captcha_enabled boolean DEFAULT false NOT NULL,
container_registry_cleanup_tags_service_max_list_size integer DEFAULT 200 NOT NULL,
+ invisible_captcha_enabled boolean DEFAULT false NOT NULL,
enforce_ssh_key_expiration boolean DEFAULT false NOT NULL,
git_two_factor_session_expiry integer DEFAULT 15 NOT NULL,
keep_latest_artifact boolean DEFAULT true NOT NULL,
@@ -9475,7 +9475,7 @@ CREATE TABLE application_settings (
asset_proxy_whitelist text,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
- CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)),
+ CONSTRAINT check_17d9558205 CHECK ((char_length(kroki_url) <= 1024)),
CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)),
CONSTRAINT check_51700b31b5 CHECK ((char_length(default_branch_name) <= 255)),
CONSTRAINT check_57123c9593 CHECK ((char_length(help_page_documentation_base_url) <= 255)),
@@ -14675,7 +14675,8 @@ CREATE TABLE namespaces (
shared_runners_enabled boolean DEFAULT true NOT NULL,
allow_descendants_override_disabled_shared_runners boolean DEFAULT false NOT NULL,
traversal_ids integer[] DEFAULT '{}'::integer[] NOT NULL,
- delayed_project_removal boolean DEFAULT false NOT NULL
+ delayed_project_removal boolean DEFAULT false NOT NULL,
+ resource_access_tokens_enabled boolean DEFAULT true NOT NULL
);
CREATE SEQUENCE namespaces_id_seq
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 496fe178c77..3c258841607 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -1198,10 +1198,12 @@ An edge in a connection.
| `detailedStatus` | [`DetailedStatus`](#detailedstatus) | Detailed status of the job. |
| `duration` | [`Int`](#int) | Duration of the job in seconds. |
| `finishedAt` | [`Time`](#time) | When a job has finished running. |
+| `id` | [`ID!`](#id) | ID of the job. |
| `name` | [`String`](#string) | Name of the job. |
| `needs` | [`CiBuildNeedConnection`](#cibuildneedconnection) | References to builds that must complete before the jobs run. |
| `pipeline` | [`Pipeline`](#pipeline) | Pipeline the job belongs to. |
| `scheduledAt` | [`Time`](#time) | Schedule for the build. |
+| `shortSha` | [`String!`](#string) | Short SHA1 ID of the commit. |
### `CiJobArtifact`
diff --git a/doc/integration/vault.md b/doc/integration/vault.md
index 362ae36389b..06f8a452427 100644
--- a/doc/integration/vault.md
+++ b/doc/integration/vault.md
@@ -76,15 +76,25 @@ The following assumes you already have Vault installed and running.
This configuration is saved under the name of the role you are creating. In this case, we are creating a `demo` role. Later, we show how you can access this role through the Vault CLI.
+ WARNING:
+ If you're using a public GitLab instance (GitLab.com or any other instance publicly
+ accessible), it's paramount to specify the `bound_claims` to allow access only to
+ members of your group/project. Otherwise, anyone with a public account can access
+ your Vault instance.
+
```shell
- vault write auth/oidc/role/demo \
- user_claim="sub" \
- allowed_redirect_uris="http://localhost:8250/oidc/callback,http://127.0.0.1:8200/ui/vault/auth/oidc/oidc/callback" \
- bound_audiences="your_application_id" \
- role_type="oidc" \
- oidc_scopes="openid" \
- policies=demo \
- ttl=1h
+ vault write auth/oidc/role/demo -<<EOF
+ {
+ "user_claim": "sub",
+ "allowed_redirect_uris": "your_vault_instance_redirect_uris",
+ "bound_audiences": "your_application_id",
+ "oidc_scopes": "openid",
+ "role_type": "oidc",
+ "policies": "demo",
+ "ttl": "1h",
+ "bound_claims": { "groups": ["yourGroup/yourSubgrup"] }
+ }
+ EOF
```
1. **Sign in to Vault:**
diff --git a/doc/user/admin_area/credentials_inventory.md b/doc/user/admin_area/credentials_inventory.md
index 053cee82634..a75c3517027 100644
--- a/doc/user/admin_area/credentials_inventory.md
+++ b/doc/user/admin_area/credentials_inventory.md
@@ -56,10 +56,14 @@ The instance then notifies the user.
## Review existing GPG keys
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/282429) in GitLab 13.10.
-> - It's [deployed behind a feature flag](../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-the-gpg-keys-view).
+> - It was [deployed behind a feature flag](../feature_flags.md), disabled by default.
+> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/292961) on GitLab 13.11.
+> - It's enabled on GitLab.com.
+> - It's recommended for production use.
+> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-the-gpg-keys-view).
+
+WARNING:
+This feature might not be available to you. Check the **version history** note above for details.
You can view all existing GPG in your GitLab instance by navigating to the
credentials inventory GPG Keys tab, as well as the following properties:
@@ -72,10 +76,10 @@ credentials inventory GPG Keys tab, as well as the following properties:
### Enable or disable the GPG keys view
-Enabling or disabling the GPG keys view is under development and not ready for production use. It is
-deployed behind a feature flag that is **disabled by default**.
+Enabling or disabling the GPG keys view 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/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index f87ea8edc7b..f82b5be2abc 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -183,10 +183,11 @@ The following variables are used for configuring specific analyzers (used for a
| `BUNDLER_AUDIT_ADVISORY_DB_URL` | `bundler-audit` | `https://github.com/rubysec/ruby-advisory-db` | URL of the advisory database used by bundler-audit. |
| `BUNDLER_AUDIT_ADVISORY_DB_REF_NAME` | `bundler-audit` | `master` | Git ref for the advisory database specified by `BUNDLER_AUDIT_ADVISORY_DB_URL`. |
| `GEMNASIUM_DB_LOCAL_PATH` | `gemnasium` | `/gemnasium-db` | Path to local Gemnasium database. |
+| `GEMNASIUM_DB_UPDATE_DISABLED` | `gemnasium` | `"false"` | Disable automatic updates for the `gemnasium-db` advisory database (For usage see: [examples](#hosting-a-copy-of-the-gemnasium_db-advisory-database))|
| `GEMNASIUM_DB_REMOTE_URL` | `gemnasium` | `https://gitlab.com/gitlab-org/security-products/gemnasium-db.git` | Repository URL for fetching the Gemnasium database. |
| `GEMNASIUM_DB_REF_NAME` | `gemnasium` | `master` | Branch name for remote repository database. `GEMNASIUM_DB_REMOTE_URL` is required. |
| `DS_REMEDIATE` | `gemnasium` | `"true"` | Enable automatic remediation of vulnerable dependencies. |
-| `DS_JAVA_VERSION` | `gemnasium-maven` | `11` | Version of Java. Available versions: `8`, `11`, `13`, `14`. Maven and Gradle use the Java version specified by this value. |
+| `DS_JAVA_VERSION` | `gemnasium-maven` | `11` | Version of Java. Available versions: `8`, `11`, `13`, `14`, `15`. Maven and Gradle use the Java version specified by this value. |
| `MAVEN_CLI_OPTS` | `gemnasium-maven` | `"-DskipTests --batch-mode"` | List of command line arguments that are passed to `maven` by the analyzer. See an example for [using private repositories](../index.md#using-private-maven-repositories). |
| `GRADLE_CLI_OPTS` | `gemnasium-maven` | | List of command line arguments that are passed to `gradle` by the analyzer. |
| `SBT_CLI_OPTS` | `gemnasium-maven` | | List of command-line arguments that the analyzer passes to `sbt`. |
@@ -505,6 +506,50 @@ ensure that it can reach your private repository. Here is an example configurati
setuptools.ssl_support.cert_paths = ['internal.crt']
```
+## Hosting a copy of the gemnasium_db advisory database
+
+The [gemnasium_db](https://gitlab.com/gitlab-org/security-products/gemnasium-db) Git repository is
+used by `gemnasium`, `gemnasium-maven`, and `gemnasium-python` as the source of vulnerability data.
+This repository updates at scan time to fetch the latest advisories. However, due to a restricted
+networking environment, running this update is sometimes not possible. In this case, a user can do
+one of the following:
+
+- [Host a copy of the advisory database](#host-a-copy-of-the-advisory-database)
+- [Use a local clone](#use-a-local-clone)
+
+### Host a copy of the advisory database
+
+If [gemnasium-db](https://gitlab.com/gitlab-org/security-products/gemnasium-db) is not reachable
+from within the environment, the user can host their own Git copy. Then the analyzer can be
+instructed to update the database from the user's copy by using `GEMNASIUM_DB_REMOTE_URL`:
+
+```yaml
+variables:
+ GEMNASIUM_DB_REMOTE_URL: https://users-own-copy.example.com/gemnasium-db/.git
+
+...
+```
+
+### Use a local clone
+
+If a hosted copy is not possible, then the user can clone [gemnasium-db](https://gitlab.com/gitlab-org/security-products/gemnasium-db)
+or create an archive before the scan and point the analyzer to the directory (using:
+`GEMNASIUM_DB_LOCAL_PATH`). Turn off the analyzer's self-update mechanism (using:
+`GEMNASIUM_DB_UPDATE_DISABLED`). In this example, the database directory is created in the
+`before_script`, before the `gemnasium` analyzer's scan job:
+
+```yaml
+...
+
+gemnasium-dependency_scanning:
+ variables:
+ GEMNASIUM_DB_LOCAL_PATH: ./gemnasium-db-local
+ GEMNASIUM_DB_UPDATE_DISABLED: "true"
+ before_script:
+ - mkdir $GEMNASIUM_DB_LOCAL_PATH
+ - tar -xzf gemnasium_db.tar.gz -C $GEMNASIUM_DB_LOCAL_PATH
+```
+
## Limitations
### Referencing local dependencies using a path in JavaScript projects
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index 35374812b37..e995a6c4e72 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -168,6 +168,10 @@ As the app is developed by OneLogin, please reach out to OneLogin if you encount
## User access and linking setup
+During the synchronization process, all of your users get GitLab accounts, welcoming them
+to their respective groups, with an invitation email. When implementing SCIM provisioning,
+you may want to warn your security-conscious employees about this email.
+
The following diagram is a general outline on what happens when you add users to your SCIM app:
```mermaid
@@ -202,10 +206,6 @@ Upon the next sync, the user is deprovisioned, which means that the user is remo
NOTE:
Deprovisioning does not delete the user account.
-During the synchronization process, all of your users get GitLab accounts, welcoming them
-to their respective groups, with an invitation email. When implementing SCIM provisioning,
-you may want to warn your security-conscious employees about this email.
-
```mermaid
graph TD
A[Remove User from SCIM app] -->|IdP sends request to GitLab| B(GitLab: Is the user part of the group?)
diff --git a/doc/user/project/import/phabricator.md b/doc/user/project/import/phabricator.md
index 189afac1226..91fd7b8928b 100644
--- a/doc/user/project/import/phabricator.md
+++ b/doc/user/project/import/phabricator.md
@@ -36,13 +36,4 @@ of the project being imported into, then the user will be linked.
## Enabling this feature
-While this feature is incomplete, a feature flag is required to enable it so that
-we can gain early feedback before releasing it for everyone. To enable it:
-
-1. Run the following command in a Rails console:
-
- ```ruby
- Feature.enable(:phabricator_import)
- ```
-
-1. Enable Phabricator as an [import source](../../admin_area/settings/visibility_and_access_controls.md#import-sources) in the Admin Area.
+Enable Phabricator as an [import source](../../admin_area/settings/visibility_and_access_controls.md#import-sources) in the Admin Area.
diff --git a/lib/gitlab/phabricator_import.rb b/lib/gitlab/phabricator_import.rb
index 3885a9934d5..4c9d54a93ce 100644
--- a/lib/gitlab/phabricator_import.rb
+++ b/lib/gitlab/phabricator_import.rb
@@ -5,7 +5,7 @@ module Gitlab
BaseError = Class.new(StandardError)
def self.available?
- Feature.enabled?(:phabricator_import) &&
+ Feature.enabled?(:phabricator_import, default_enabled: :yaml) &&
Gitlab::CurrentSettings.import_sources.include?('phabricator')
end
end
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 00739c05386..1082d63724c 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -385,11 +385,11 @@ module Gitlab
end
def merge_request_wip
- /(?i)(\[WIP\]\s*|WIP:\s*|WIP$)/
+ /(?i)(\[WIP\]\s*|WIP:\s*|\AWIP\z)/
end
def merge_request_draft
- /(?i)(\[draft\]|\(draft\)|draft:|draft\s\-\s|draft$)/
+ /\A(?i)(\[draft\]|\(draft\)|draft:|draft\s\-\s|draft\z)/
end
def issue
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 8e147f5d143..96c0cbcf327 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -17073,6 +17073,9 @@ msgstr ""
msgid "Issue weight"
msgstr ""
+msgid "Issue(s) already assigned"
+msgstr ""
+
msgid "IssueAnalytics|Age"
msgstr ""
@@ -20717,7 +20720,7 @@ msgstr ""
msgid "No estimate or time spent"
msgstr ""
-msgid "No file chosen"
+msgid "No file chosen."
msgstr ""
msgid "No file hooks found."
@@ -20768,6 +20771,9 @@ msgstr ""
msgid "No matches found"
msgstr ""
+msgid "No matching issue found. Make sure that you are adding a valid issue URL."
+msgstr ""
+
msgid "No matching labels"
msgstr ""
@@ -23380,7 +23386,7 @@ msgstr ""
msgid "Profiles|Main settings"
msgstr ""
-msgid "Profiles|No file chosen"
+msgid "Profiles|No file chosen."
msgstr ""
msgid "Profiles|Notification email"
@@ -27277,9 +27283,6 @@ msgstr ""
msgid "Select projects"
msgstr ""
-msgid "Select required regulatory standard."
-msgstr ""
-
msgid "Select reviewer(s)"
msgstr ""
diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb
index 9b803edd463..0685e5a2055 100644
--- a/spec/controllers/projects/registry/repositories_controller_spec.rb
+++ b/spec/controllers/projects/registry/repositories_controller_spec.rb
@@ -16,19 +16,19 @@ RSpec.describe Projects::Registry::RepositoriesController do
project.add_developer(user)
end
- shared_examples 'with name parameter' do
- let_it_be(:repo) { create(:container_repository, project: project, name: 'my_searched_image') }
- let_it_be(:another_repo) { create(:container_repository, project: project, name: 'bar') }
-
- it 'returns the searched repo' do
- go_to_index(format: :json, params: { name: 'my_searched_image' })
+ shared_examples 'renders 200 for html and 404 for json' do
+ it 'successfully renders container repositories', :snowplow do
+ go_to_index
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response.length).to eq 1
- expect(json_response.first).to include(
- 'id' => repo.id,
- 'name' => repo.name
- )
+ # event tracked in GraphQL API: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44926
+ expect_no_snowplow_event
+ end
+
+ it 'returns 404 for request in json format' do
+ go_to_index(format: :json)
+
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -50,33 +50,12 @@ RSpec.describe Projects::Registry::RepositoriesController do
tags: %w[rc1 latest])
end
- it 'successfully renders container repositories', :snowplow do
- go_to_index
-
- expect_no_snowplow_event
- expect(response).to have_gitlab_http_status(:ok)
- end
-
- it 'tracks the event', :snowplow do
- go_to_index(format: :json)
-
- expect_snowplow_event(category: anything, action: 'list_repositories')
- end
-
it 'creates a root container repository' do
expect { go_to_index }.to change { ContainerRepository.all.count }.by(1)
expect(ContainerRepository.first).to be_root_repository
end
- it 'json has a list of projects' do
- go_to_index(format: :json)
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('registry/repositories')
- expect(response).to include_pagination_headers
- end
-
- it_behaves_like 'with name parameter'
+ it_behaves_like 'renders 200 for html and 404 for json'
end
context 'when there are no tags for this repository' do
@@ -84,22 +63,11 @@ RSpec.describe Projects::Registry::RepositoriesController do
stub_container_registry_tags(repository: :any, tags: [])
end
- it 'successfully renders container repositories' do
- go_to_index
-
- expect(response).to have_gitlab_http_status(:ok)
- end
-
it 'does not ensure root container repository' do
expect { go_to_index }.not_to change { ContainerRepository.all.count }
end
- it 'responds with json if asked' do
- go_to_index(format: :json)
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_kind_of(Array)
- end
+ it_behaves_like 'renders 200 for html and 404 for json'
end
end
end
diff --git a/spec/frontend/environments/enable_review_app_modal_spec.js b/spec/frontend/environments/enable_review_app_modal_spec.js
index f5063cff620..9a3f13f19d5 100644
--- a/spec/frontend/environments/enable_review_app_modal_spec.js
+++ b/spec/frontend/environments/enable_review_app_modal_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import EnableReviewAppButton from '~/environments/components/enable_review_app_modal.vue';
import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
@@ -11,15 +12,25 @@ describe('Enable Review App Button', () => {
describe('renders the modal', () => {
beforeEach(() => {
- wrapper = shallowMount(EnableReviewAppButton, {
- propsData: {
- modalId: 'fake-id',
- },
- });
+ wrapper = extendedWrapper(
+ shallowMount(EnableReviewAppButton, {
+ propsData: {
+ modalId: 'fake-id',
+ },
+ provide: {
+ defaultBranchName: 'main',
+ },
+ }),
+ );
+ });
+
+ it('renders the defaultBranchName copy', () => {
+ const findCopyString = () => wrapper.findByTestId('enable-review-app-copy-string');
+ expect(findCopyString().text()).toContain('- main');
});
it('renders the copyToClipboard button', () => {
- expect(wrapper.find(ModalCopyButton).exists()).toBe(true);
+ expect(wrapper.findComponent(ModalCopyButton).exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/mr_notes/stores/actions_spec.js b/spec/frontend/mr_notes/stores/actions_spec.js
new file mode 100644
index 00000000000..dbceedface1
--- /dev/null
+++ b/spec/frontend/mr_notes/stores/actions_spec.js
@@ -0,0 +1,25 @@
+import testAction from 'helpers/vuex_action_helper';
+import { setEndpoints } from '~/mr_notes/stores/actions';
+import mutationTypes from '~/mr_notes/stores/mutation_types';
+
+describe('MR Notes Mutator Actions', () => {
+ describe('setEndpoints', () => {
+ it('should trigger the SET_ENDPOINTS state mutation', (done) => {
+ const endpoints = { endpointA: 'a' };
+
+ testAction(
+ setEndpoints,
+ endpoints,
+ {},
+ [
+ {
+ type: mutationTypes.SET_ENDPOINTS,
+ payload: endpoints,
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/mr_notes/stores/mutations_spec.js b/spec/frontend/mr_notes/stores/mutations_spec.js
new file mode 100644
index 00000000000..422db3d5a38
--- /dev/null
+++ b/spec/frontend/mr_notes/stores/mutations_spec.js
@@ -0,0 +1,15 @@
+import mutationTypes from '~/mr_notes/stores/mutation_types';
+import mutations from '~/mr_notes/stores/mutations';
+
+describe('MR Notes Mutations', () => {
+ describe(mutationTypes.SET_ENDPOINTS, () => {
+ it('should set the endpoints value', () => {
+ const state = {};
+ const endpoints = { endpointA: 'A', endpointB: 'B' };
+
+ mutations[mutationTypes.SET_ENDPOINTS](state, endpoints);
+
+ expect(state.endpoints).toEqual(endpoints);
+ });
+ });
+});
diff --git a/spec/frontend/repository/components/__snapshots__/directory_download_links_spec.js.snap b/spec/frontend/repository/components/__snapshots__/directory_download_links_spec.js.snap
index 6968fb3e153..836ae5c22e6 100644
--- a/spec/frontend/repository/components/__snapshots__/directory_download_links_spec.js.snap
+++ b/spec/frontend/repository/components/__snapshots__/directory_download_links_spec.js.snap
@@ -16,22 +16,30 @@ exports[`Repository directory download links component renders downloads links f
<div
class="btn-group ml-0 w-100"
>
- <gl-link-stub
- class="btn btn-xs btn-primary"
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
href="http://test.com/?path=app"
+ icon=""
+ size="small"
+ variant="confirm"
>
zip
- </gl-link-stub>
- <gl-link-stub
- class="btn btn-xs"
+ </gl-button-stub>
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
href="http://test.com/?path=app"
+ icon=""
+ size="small"
+ variant="default"
>
tar
- </gl-link-stub>
+ </gl-button-stub>
</div>
</div>
</section>
@@ -53,22 +61,30 @@ exports[`Repository directory download links component renders downloads links f
<div
class="btn-group ml-0 w-100"
>
- <gl-link-stub
- class="btn btn-xs btn-primary"
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
href="http://test.com/?path=app/assets"
+ icon=""
+ size="small"
+ variant="confirm"
>
zip
- </gl-link-stub>
- <gl-link-stub
- class="btn btn-xs"
+ </gl-button-stub>
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
href="http://test.com/?path=app/assets"
+ icon=""
+ size="small"
+ variant="default"
>
tar
- </gl-link-stub>
+ </gl-button-stub>
</div>
</div>
</section>
diff --git a/spec/graphql/resolvers/group_milestones_resolver_spec.rb b/spec/graphql/resolvers/group_milestones_resolver_spec.rb
index d8ff8e9c1f2..dd3f1676538 100644
--- a/spec/graphql/resolvers/group_milestones_resolver_spec.rb
+++ b/spec/graphql/resolvers/group_milestones_resolver_spec.rb
@@ -136,5 +136,56 @@ RSpec.describe Resolvers::GroupMilestonesResolver do
expect(resolve_group_milestones(args)).to match_array([milestone1, milestone2, milestone3])
end
end
+
+ describe 'include_descendants and include_ancestors' do
+ let_it_be(:parent_group) { create(:group, :public) }
+ let_it_be(:group) { create(:group, :public, parent: parent_group) }
+ let_it_be(:accessible_group) { create(:group, :private, parent: group) }
+ let_it_be(:accessible_project) { create(:project, group: accessible_group) }
+ let_it_be(:inaccessible_group) { create(:group, :private, parent: group) }
+ let_it_be(:inaccessible_project) { create(:project, :private, group: group) }
+ let_it_be(:milestone1) { create(:milestone, group: group) }
+ let_it_be(:milestone2) { create(:milestone, group: accessible_group) }
+ let_it_be(:milestone3) { create(:milestone, project: accessible_project) }
+ let_it_be(:milestone4) { create(:milestone, group: inaccessible_group) }
+ let_it_be(:milestone5) { create(:milestone, project: inaccessible_project) }
+ let_it_be(:milestone6) { create(:milestone, group: parent_group) }
+
+ before do
+ accessible_group.add_developer(current_user)
+ end
+
+ context 'when including neither ancestor or descendant milestones in a public group' do
+ let(:args) { {} }
+
+ it 'finds milestones only in accessible projects and groups' do
+ expect(resolve_group_milestones(args)).to match_array([milestone1])
+ end
+ end
+
+ context 'when including descendant milestones in a public group' do
+ let(:args) { { include_descendants: true } }
+
+ it 'finds milestones only in accessible projects and groups' do
+ expect(resolve_group_milestones(args)).to match_array([milestone1, milestone2, milestone3])
+ end
+ end
+
+ context 'when including ancestor milestones in a public group' do
+ let(:args) { { include_ancestors: true } }
+
+ it 'finds milestones only in accessible projects and groups' do
+ expect(resolve_group_milestones(args)).to match_array([milestone1, milestone6])
+ end
+ end
+
+ context 'when including both ancestor or descendant milestones in a public group' do
+ let(:args) { { include_descendants: true, include_ancestors: true } }
+
+ it 'finds milestones only in accessible projects and groups' do
+ expect(resolve_group_milestones(args)).to match_array([milestone1, milestone2, milestone3, milestone6])
+ end
+ end
+ end
end
end
diff --git a/spec/graphql/types/ci/job_type_spec.rb b/spec/graphql/types/ci/job_type_spec.rb
index 25f626cea0f..c54137a1c3e 100644
--- a/spec/graphql/types/ci/job_type_spec.rb
+++ b/spec/graphql/types/ci/job_type_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe Types::Ci::JobType do
it 'exposes the expected fields' do
expected_fields = %i[
+ id
+ shortSha
pipeline
name
needs
diff --git a/spec/initializers/kramdown_patch_spec.rb b/spec/initializers/kramdown_patch_spec.rb
new file mode 100644
index 00000000000..49dda9252bb
--- /dev/null
+++ b/spec/initializers/kramdown_patch_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Kramdown patch for syntax highlighting formatters' do
+ subject { Kramdown::Document.new(options + "\n" + code).to_html }
+
+ let(:code) do
+ <<-RUBY
+~~~ ruby
+ def what?
+ 42
+ end
+~~~
+ RUBY
+ end
+
+ context 'with invalid formatter' do
+ let(:options) { %({::options auto_ids="false" footnote_nr="5" syntax_highlighter="rouge" syntax_highlighter_opts="{formatter: CSV, line_numbers: true\\}" /}) }
+
+ it 'falls back to standard HTML and disallows CSV' do
+ expect(CSV).not_to receive(:new)
+ expect(::Rouge::Formatters::HTML).to receive(:new).and_call_original
+
+ expect(subject).to be_present
+ end
+ end
+
+ context 'with valid formatter' do
+ let(:options) { %({::options auto_ids="false" footnote_nr="5" syntax_highlighter="rouge" syntax_highlighter_opts="{formatter: HTMLLegacy\\}" /}) }
+
+ it 'allows formatter' do
+ expect(::Rouge::Formatters::HTMLLegacy).to receive(:new).and_call_original
+
+ expect(subject).to be_present
+ end
+ end
+end
diff --git a/spec/models/experiment_spec.rb b/spec/models/experiment_spec.rb
index 09dd1766acc..1517f426fa3 100644
--- a/spec/models/experiment_spec.rb
+++ b/spec/models/experiment_spec.rb
@@ -244,18 +244,27 @@ RSpec.describe Experiment do
context 'when no existing experiment_subject record exists for the given group' do
it 'creates an experiment_subject record' do
- expect_next(ExperimentSubject).to receive(:update!).with(variant: variant).and_call_original
-
expect { record_group_and_variant! }.to change(ExperimentSubject, :count).by(1)
+ expect(ExperimentSubject.last.variant).to eq(variant.to_s)
end
end
context 'when an existing experiment_subject exists for the given group' do
- context 'but it belonged to a different variant' do
- let!(:experiment_subject) do
- create(:experiment_subject, experiment: experiment, group: group, user: nil, variant: :experimental)
+ let_it_be(:experiment_subject) do
+ create(:experiment_subject, experiment: experiment, group: group, user: nil, variant: :experimental)
+ end
+
+ context 'when it belongs to the same variant' do
+ let(:variant) { :experimental }
+
+ it 'does not initiate a transaction' do
+ expect(ActiveRecord::Base.connection).not_to receive(:transaction)
+
+ subject
end
+ end
+ context 'but it belonged to a different variant' do
it 'updates the variant value' do
expect { record_group_and_variant! }.to change { experiment_subject.reload.variant }.to('control')
end
@@ -299,6 +308,16 @@ RSpec.describe Experiment do
expect { subject }.not_to change(ExperimentUser, :count)
end
+ context 'when group type or context did not change' do
+ let(:context) { {} }
+
+ it 'does not initiate a transaction' do
+ expect(ActiveRecord::Base.connection).not_to receive(:transaction)
+
+ subject
+ end
+ end
+
context 'but the group_type and context has changed' do
let(:group) { :experimental }
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 8c7289adbcc..b2c45135de1 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -1353,6 +1353,24 @@ RSpec.describe MergeRequest, factory_default: :keep do
expect(subject.work_in_progress?).to eq false
end
+ it 'does not detect Draft: in the middle of the title' do
+ subject.title = 'Something with Draft: in the middle'
+
+ expect(subject.work_in_progress?).to eq false
+ end
+
+ it 'does not detect WIP at the end of the title' do
+ subject.title = 'Something ends with WIP'
+
+ expect(subject.work_in_progress?).to eq false
+ end
+
+ it 'does not detect Draft at the end of the title' do
+ subject.title = 'Something ends with Draft'
+
+ expect(subject.work_in_progress?).to eq false
+ end
+
it "doesn't detect WIP for words starting with WIP" do
subject.title = "Wipwap #{subject.title}"
expect(subject.work_in_progress?).to eq false
@@ -1363,6 +1381,11 @@ RSpec.describe MergeRequest, factory_default: :keep do
expect(subject.work_in_progress?).to eq false
end
+ it "doesn't detect draft for words containing with draft" do
+ subject.title = "Drafting #{subject.title}"
+ expect(subject.work_in_progress?).to eq false
+ end
+
it "doesn't detect WIP by default" do
expect(subject.work_in_progress?).to eq false
end
@@ -1393,6 +1416,42 @@ RSpec.describe MergeRequest, factory_default: :keep do
expect(subject.work_in_progress?).to eq false
end
end
+
+ it 'removes only WIP prefix from the MR title' do
+ subject.title = 'WIP: Implement feature called WIP'
+
+ expect(subject.wipless_title).to eq 'Implement feature called WIP'
+ end
+
+ it 'removes only draft prefix from the MR title' do
+ subject.title = 'Draft: Implement feature called draft'
+
+ expect(subject.wipless_title).to eq 'Implement feature called draft'
+ end
+
+ it 'does not remove WIP in the middle of the title' do
+ subject.title = 'Something with WIP in the middle'
+
+ expect(subject.wipless_title).to eq subject.title
+ end
+
+ it 'does not remove Draft in the middle of the title' do
+ subject.title = 'Something with Draft in the middle'
+
+ expect(subject.wipless_title).to eq subject.title
+ end
+
+ it 'does not remove WIP at the end of the title' do
+ subject.title = 'Something ends with WIP'
+
+ expect(subject.wipless_title).to eq subject.title
+ end
+
+ it 'does not remove Draft at the end of the title' do
+ subject.title = 'Something ends with Draft'
+
+ expect(subject.wipless_title).to eq subject.title
+ end
end
describe "#wip_title" do
diff --git a/spec/requests/api/graphql/group/milestones_spec.rb b/spec/requests/api/graphql/group/milestones_spec.rb
index 380eaea17f8..a5b489d72fd 100644
--- a/spec/requests/api/graphql/group/milestones_spec.rb
+++ b/spec/requests/api/graphql/group/milestones_spec.rb
@@ -9,12 +9,14 @@ RSpec.describe 'Milestones through GroupQuery' do
let_it_be(:now) { Time.now }
describe 'Get list of milestones from a group' do
- let_it_be(:group) { create(:group) }
+ let_it_be(:parent_group) { create(:group) }
+ let_it_be(:group) { create(:group, parent: parent_group) }
let_it_be(:milestone_1) { create(:milestone, group: group) }
let_it_be(:milestone_2) { create(:milestone, group: group, state: :closed, start_date: now, due_date: now + 1.day) }
let_it_be(:milestone_3) { create(:milestone, group: group, start_date: now, due_date: now + 2.days) }
let_it_be(:milestone_4) { create(:milestone, group: group, state: :closed, start_date: now - 2.days, due_date: now - 1.day) }
let_it_be(:milestone_from_other_group) { create(:milestone, group: create(:group)) }
+ let_it_be(:parent_milestone) { create(:milestone, group: parent_group) }
let(:milestone_data) { graphql_data['group']['milestones']['edges'] }
@@ -64,14 +66,32 @@ RSpec.describe 'Milestones through GroupQuery' do
accessible_group.add_developer(user)
end
- it 'returns milestones also from subgroups and subprojects visible to user' do
- fetch_milestones(user, args)
+ context 'when including decendants' do
+ let(:args) { { include_descendants: true } }
+
+ it 'returns milestones also from subgroups and subprojects visible to user' do
+ fetch_milestones(user, args)
+
+ expect_array_response(
+ milestone_1.to_global_id.to_s, milestone_2.to_global_id.to_s,
+ milestone_3.to_global_id.to_s, milestone_4.to_global_id.to_s,
+ submilestone_1.to_global_id.to_s, submilestone_2.to_global_id.to_s
+ )
+ end
+ end
+
+ context 'when including ancestors' do
+ let(:args) { { include_ancestors: true } }
- expect_array_response(
- milestone_1.to_global_id.to_s, milestone_2.to_global_id.to_s,
- milestone_3.to_global_id.to_s, milestone_4.to_global_id.to_s,
- submilestone_1.to_global_id.to_s, submilestone_2.to_global_id.to_s
- )
+ it 'returns milestones from ancestor groups' do
+ fetch_milestones(user, args)
+
+ expect_array_response(
+ milestone_1.to_global_id.to_s, milestone_2.to_global_id.to_s,
+ milestone_3.to_global_id.to_s, milestone_4.to_global_id.to_s,
+ parent_milestone.to_global_id.to_s
+ )
+ end
end
end
diff --git a/spec/requests/api/issue_links_spec.rb b/spec/requests/api/issue_links_spec.rb
index a4243766111..b64d395f25f 100644
--- a/spec/requests/api/issue_links_spec.rb
+++ b/spec/requests/api/issue_links_spec.rb
@@ -82,7 +82,7 @@ RSpec.describe API::IssueLinks do
params: { target_project_id: unauthorized_project.id, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:not_found)
- expect(json_response['message']).to eq('No Issue found for given params')
+ expect(json_response['message']).to eq('No matching issue found. Make sure that you are adding a valid issue URL.')
end
end
diff --git a/spec/requests/projects/issue_links_controller_spec.rb b/spec/requests/projects/issue_links_controller_spec.rb
index a21c676f000..d22955718f8 100644
--- a/spec/requests/projects/issue_links_controller_spec.rb
+++ b/spec/requests/projects/issue_links_controller_spec.rb
@@ -71,7 +71,7 @@ RSpec.describe Projects::IssueLinksController do
list_service_response = IssueLinks::ListService.new(issue, user).execute
expect(response).to have_gitlab_http_status(:not_found)
- expect(json_response).to eq('message' => 'No Issue found for given params', 'issuables' => list_service_response.as_json)
+ expect(json_response).to eq('message' => 'No matching issue found. Make sure that you are adding a valid issue URL.', 'issuables' => list_service_response.as_json)
end
end
end
diff --git a/spec/services/issue_links/create_service_spec.rb b/spec/services/issue_links/create_service_spec.rb
index 873890d25cf..1bca717acb7 100644
--- a/spec/services/issue_links/create_service_spec.rb
+++ b/spec/services/issue_links/create_service_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe IssueLinks::CreateService do
end
it 'returns error' do
- is_expected.to eq(message: 'No Issue found for given params', status: :error, http_status: 404)
+ is_expected.to eq(message: 'No matching issue found. Make sure that you are adding a valid issue URL.', status: :error, http_status: 404)
end
end
@@ -34,7 +34,7 @@ RSpec.describe IssueLinks::CreateService do
end
it 'returns error' do
- is_expected.to eq(message: 'No Issue found for given params', status: :error, http_status: 404)
+ is_expected.to eq(message: 'No matching issue found. Make sure that you are adding a valid issue URL.', status: :error, http_status: 404)
end
it 'no relationship is created' do
@@ -52,7 +52,7 @@ RSpec.describe IssueLinks::CreateService do
it 'returns error' do
target_issuable.project.add_guest(user)
- is_expected.to eq(message: 'No Issue found for given params', status: :error, http_status: 404)
+ is_expected.to eq(message: 'No matching issue found. Make sure that you are adding a valid issue URL.', status: :error, http_status: 404)
end
it 'no relationship is created' do
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 5f1513b1247..5ffc9d778d1 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -104,9 +104,9 @@ RSpec.configure do |config|
warn "=== uptime"
warn `uptime`
warn "=== Prometheus metrics:"
- warn `curl -s http://localhost:9236/metrics`
+ warn `curl -s -o log/gitaly-metrics.log http://localhost:9236/metrics`
warn "=== Taking goroutine dump in log/goroutines.log..."
- warn `curl -o log/goroutines.log http://localhost:9236/debug/pprof/goroutine?debug=2`
+ warn `curl -s -o log/goroutines.log http://localhost:9236/debug/pprof/goroutine?debug=2`
end
end
end