Add latest changes from gitlab-org/gitlab@master
|
@ -684,8 +684,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
|
|||
- spec/models/terraform/state_spec.rb
|
||||
- spec/models/u2f_registration_spec.rb
|
||||
- spec/models/user_spec.rb
|
||||
- spec/models/wiki_page/meta_spec.rb
|
||||
- spec/models/wiki_page_spec.rb
|
||||
- spec/requests/api/api_spec.rb
|
||||
- spec/requests/api/award_emoji_spec.rb
|
||||
- spec/requests/api/branches_spec.rb
|
||||
|
|
|
@ -1 +1 @@
|
|||
c2c12e3152bfc6c899b5ad08974659ac7b450232
|
||||
ffbce774bce90b5a65f5b235afe492a7266aa82f
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<script>
|
||||
import { GlEmptyState } from '@gitlab/ui';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { s__ } from '~/locale';
|
||||
|
||||
export const i18n = {
|
||||
noTestsButton: s__('TestReports|Learn more about pipeline test reports'),
|
||||
noTestsDescription: s__('TestReports|No test cases were found in the test report.'),
|
||||
noTestsTitle: s__('TestReports|There are no tests to display'),
|
||||
noReportsButton: s__('TestReports|Learn how to upload pipeline test reports'),
|
||||
noReportsDescription: s__(
|
||||
'TestReports|You can configure your job to use unit test reports, and GitLab displays a report here and in the related merge request.',
|
||||
),
|
||||
noReportsTitle: s__('TestReports|There are no test reports for this pipeline'),
|
||||
};
|
||||
|
||||
export default {
|
||||
i18n,
|
||||
components: {
|
||||
GlEmptyState,
|
||||
},
|
||||
inject: {
|
||||
emptyStateImagePath: {
|
||||
default: '',
|
||||
},
|
||||
hasTestReport: {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
emptyStateText() {
|
||||
if (this.hasTestReport) {
|
||||
return {
|
||||
button: this.$options.i18n.noTestsButton,
|
||||
description: this.$options.i18n.noTestsDescription,
|
||||
title: this.$options.i18n.noTestsTitle,
|
||||
};
|
||||
}
|
||||
return {
|
||||
button: this.$options.i18n.noReportsButton,
|
||||
description: this.$options.i18n.noReportsDescription,
|
||||
title: this.$options.i18n.noReportsTitle,
|
||||
};
|
||||
},
|
||||
testReportDocPath() {
|
||||
return helpPagePath('ci/unit_test_reports');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-empty-state
|
||||
:title="emptyStateText.title"
|
||||
:description="emptyStateText.description"
|
||||
:svg-path="emptyStateImagePath"
|
||||
:primary-button-link="testReportDocPath"
|
||||
:primary-button-text="emptyStateText.button"
|
||||
/>
|
||||
</template>
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import EmptyState from './empty_state.vue';
|
||||
import TestSuiteTable from './test_suite_table.vue';
|
||||
import TestSummary from './test_summary.vue';
|
||||
import TestSummaryTable from './test_summary_table.vue';
|
||||
|
@ -8,11 +9,17 @@ import TestSummaryTable from './test_summary_table.vue';
|
|||
export default {
|
||||
name: 'TestReports',
|
||||
components: {
|
||||
EmptyState,
|
||||
GlLoadingIcon,
|
||||
TestSuiteTable,
|
||||
TestSummary,
|
||||
TestSummaryTable,
|
||||
},
|
||||
inject: {
|
||||
hasTestReport: {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(['isLoading', 'selectedSuiteIndex', 'testReports']),
|
||||
...mapGetters(['getSelectedSuite']),
|
||||
|
@ -25,7 +32,9 @@ export default {
|
|||
},
|
||||
},
|
||||
created() {
|
||||
this.fetchSummary();
|
||||
if (this.hasTestReport) {
|
||||
this.fetchSummary();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
|
@ -83,11 +92,5 @@ export default {
|
|||
</transition>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="row gl-mt-3">
|
||||
<div class="col-12">
|
||||
<p data-testid="no-tests-to-show">{{ s__('TestReports|There are no tests to show.') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<empty-state v-else />
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Vue from 'vue';
|
||||
import { deprecatedCreateFlash as Flash } from '~/flash';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import { __ } from '~/locale';
|
||||
import Translate from '~/vue_shared/translate';
|
||||
import PipelineGraphLegacy from './components/graph/graph_component_legacy.vue';
|
||||
|
@ -63,7 +64,8 @@ const createLegacyPipelinesDetailApp = (mediator) => {
|
|||
|
||||
const createTestDetails = () => {
|
||||
const el = document.querySelector(SELECTORS.PIPELINE_TESTS);
|
||||
const { blobPath, summaryEndpoint, suiteEndpoint } = el?.dataset || {};
|
||||
const { blobPath, emptyStateImagePath, hasTestReport, summaryEndpoint, suiteEndpoint } =
|
||||
el?.dataset || {};
|
||||
const testReportsStore = createTestReportsStore({
|
||||
blobPath,
|
||||
summaryEndpoint,
|
||||
|
@ -76,6 +78,10 @@ const createTestDetails = () => {
|
|||
components: {
|
||||
TestReports,
|
||||
},
|
||||
provide: {
|
||||
emptyStateImagePath,
|
||||
hasTestReport: parseBoolean(hasTestReport),
|
||||
},
|
||||
store: testReportsStore,
|
||||
render(createElement) {
|
||||
return createElement('test-reports');
|
||||
|
|
|
@ -7,12 +7,7 @@ export const setNotification = (appEl) => {
|
|||
const notificationEl = document.querySelector('.header-help');
|
||||
let notificationCountEl = notificationEl.querySelector('.js-whats-new-notification-count');
|
||||
|
||||
const legacyStorageKey = 'display-whats-new-notification-13.10';
|
||||
const localStoragePairs = [
|
||||
[legacyStorageKey, false],
|
||||
[STORAGE_KEY, versionDigest],
|
||||
];
|
||||
if (localStoragePairs.some((pair) => localStorage.getItem(pair[0]) === pair[1].toString())) {
|
||||
if (localStorage.getItem(STORAGE_KEY) === versionDigest) {
|
||||
notificationEl.classList.remove('with-notifications');
|
||||
if (notificationCountEl) {
|
||||
notificationCountEl.parentElement.removeChild(notificationCountEl);
|
||||
|
|
|
@ -36,23 +36,11 @@ module Packages
|
|||
|
||||
def packages_with_path
|
||||
matching_packages = base.only_maven_packages_with_path(@path, use_cte: @group.present?)
|
||||
|
||||
if group_level_improvements?
|
||||
matching_packages = matching_packages.order_by_package_file if @order_by_package_file
|
||||
else
|
||||
matching_packages = matching_packages.order_by_package_file if versionless_package?(matching_packages)
|
||||
end
|
||||
matching_packages = matching_packages.order_by_package_file if @order_by_package_file
|
||||
|
||||
matching_packages
|
||||
end
|
||||
|
||||
def versionless_package?(matching_packages)
|
||||
return if matching_packages.empty?
|
||||
|
||||
# if one matching package is versionless, they all are.
|
||||
matching_packages.first&.version.nil?
|
||||
end
|
||||
|
||||
# Produces a query that retrieves packages from a single project.
|
||||
def packages_for_a_single_project
|
||||
@project.packages
|
||||
|
@ -61,11 +49,7 @@ module Packages
|
|||
# Produces a query that retrieves packages from multiple projects that
|
||||
# the current user can view within a group.
|
||||
def packages_for_multiple_projects
|
||||
if group_level_improvements?
|
||||
packages_visible_to_user(@current_user, within_group: @group)
|
||||
else
|
||||
::Packages::Package.for_projects(projects_visible_to_current_user)
|
||||
end
|
||||
packages_visible_to_user(@current_user, within_group: @group)
|
||||
end
|
||||
|
||||
# Returns the projects that the current user can view within a group.
|
||||
|
@ -73,12 +57,6 @@ module Packages
|
|||
@group.all_projects
|
||||
.public_or_visible_to_user(@current_user)
|
||||
end
|
||||
|
||||
def group_level_improvements?
|
||||
strong_memoize(:group_level_improvements) do
|
||||
Feature.enabled?(:maven_packages_group_level_improvements, default_enabled: :yaml)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,10 +8,7 @@ module Types
|
|||
argument :not, NegatedBoardIssueInputType,
|
||||
required: false,
|
||||
prepare: ->(negated_args, ctx) { negated_args.to_h },
|
||||
description: <<~MD
|
||||
List of negated arguments.
|
||||
Warning: this argument is experimental and a subject to change in future.
|
||||
MD
|
||||
description: 'List of negated arguments.'
|
||||
|
||||
argument :search, GraphQL::STRING_TYPE,
|
||||
required: false,
|
||||
|
|
|
@ -10,9 +10,10 @@ class MembersPreloader
|
|||
def preload_all
|
||||
ActiveRecord::Associations::Preloader.new.preload(members, :user)
|
||||
ActiveRecord::Associations::Preloader.new.preload(members, :source)
|
||||
ActiveRecord::Associations::Preloader.new.preload(members.map(&:user), :status)
|
||||
ActiveRecord::Associations::Preloader.new.preload(members.map(&:user), :u2f_registrations)
|
||||
ActiveRecord::Associations::Preloader.new.preload(members.map(&:user), :webauthn_registrations)
|
||||
ActiveRecord::Associations::Preloader.new.preload(members, :created_by)
|
||||
ActiveRecord::Associations::Preloader.new.preload(members, user: :status)
|
||||
ActiveRecord::Associations::Preloader.new.preload(members, user: :u2f_registrations)
|
||||
ActiveRecord::Associations::Preloader.new.preload(members, user: :webauthn_registrations)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ class Packages::Package < ApplicationRecord
|
|||
|
||||
enum status: { default: 0, hidden: 1, processing: 2, error: 3 }
|
||||
|
||||
scope :for_projects, ->(project_ids) { where(project_id: project_ids) }
|
||||
scope :with_name, ->(name) { where(name: name) }
|
||||
scope :with_name_like, ->(name) { where(arel_table[:name].matches(name)) }
|
||||
scope :with_normalized_pypi_name, ->(name) { where("LOWER(regexp_replace(name, '[-_.]+', '-', 'g')) = ?", name.downcase) }
|
||||
|
@ -137,14 +138,6 @@ class Packages::Package < ApplicationRecord
|
|||
|
||||
after_commit :update_composer_cache, on: :destroy, if: -> { composer? }
|
||||
|
||||
def self.for_projects(projects)
|
||||
unless Feature.enabled?(:maven_packages_group_level_improvements, default_enabled: :yaml)
|
||||
return none unless projects.any?
|
||||
end
|
||||
|
||||
where(project_id: projects)
|
||||
end
|
||||
|
||||
def self.only_maven_packages_with_path(path, use_cte: false)
|
||||
if use_cte && Feature.enabled?(:maven_metadata_by_path_with_optimization_fence, default_enabled: :yaml)
|
||||
# This is an optimization fence which assumes that looking up the Metadatum record by path (globally)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FlowdockService < Service
|
||||
include ActionView::Helpers::UrlHelper
|
||||
prop_accessor :token
|
||||
validates :token, presence: true, if: :activated?
|
||||
|
||||
|
@ -9,7 +10,12 @@ class FlowdockService < Service
|
|||
end
|
||||
|
||||
def description
|
||||
s_('FlowdockService|Flowdock is a collaboration web app for technical teams.')
|
||||
s_('FlowdockService|Send event notifications from GitLab to Flowdock flows.')
|
||||
end
|
||||
|
||||
def help
|
||||
docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('api/services', anchor: 'flowdock'), target: '_blank', rel: 'noopener noreferrer'
|
||||
s_('FlowdockService|Send event notifications from GitLab to Flowdock flows. %{docs_link}').html_safe % { docs_link: docs_link.html_safe }
|
||||
end
|
||||
|
||||
def self.to_param
|
||||
|
@ -18,7 +24,7 @@ class FlowdockService < Service
|
|||
|
||||
def fields
|
||||
[
|
||||
{ type: 'text', name: 'token', placeholder: s_('FlowdockService|Flowdock Git source token'), required: true }
|
||||
{ type: 'text', name: 'token', placeholder: s_('FlowdockService|1b609b52537...'), required: true, help: 'Enter your Flowdock token.' }
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
require 'hangouts_chat'
|
||||
|
||||
class HangoutsChatService < ChatNotificationService
|
||||
include ActionView::Helpers::UrlHelper
|
||||
|
||||
def title
|
||||
'Hangouts Chat'
|
||||
'Google Chat'
|
||||
end
|
||||
|
||||
def description
|
||||
'Receive event notifications in Google Hangouts Chat'
|
||||
'Send notifications from GitLab to a room in Google Chat.'
|
||||
end
|
||||
|
||||
def self.to_param
|
||||
|
@ -16,13 +18,8 @@ class HangoutsChatService < ChatNotificationService
|
|||
end
|
||||
|
||||
def help
|
||||
'This service sends notifications about projects events to Google Hangouts Chat room.<br />
|
||||
To set up this service:
|
||||
<ol>
|
||||
<li><a href="https://developers.google.com/hangouts/chat/how-tos/webhooks">Set up an incoming webhook for your room</a>. All notifications will come to this room.</li>
|
||||
<li>Paste the <strong>Webhook URL</strong> into the field below.</li>
|
||||
<li>Select events below to enable notifications.</li>
|
||||
</ol>'
|
||||
docs_link = link_to _('How do I set up a Google Chat webhook?'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/hangouts_chat'), target: '_blank', rel: 'noopener noreferrer'
|
||||
s_('Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}').html_safe % { docs_link: docs_link.html_safe }
|
||||
end
|
||||
|
||||
def event_field(event)
|
||||
|
@ -42,7 +39,7 @@ class HangoutsChatService < ChatNotificationService
|
|||
|
||||
def default_fields
|
||||
[
|
||||
{ type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" },
|
||||
{ type: 'text', name: 'webhook', placeholder: "#{webhook_placeholder}" },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
|
||||
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices }
|
||||
]
|
||||
|
|
|
@ -30,7 +30,8 @@ class UserCallout < ApplicationRecord
|
|||
new_user_signups_cap_reached: 26, # EE-only
|
||||
unfinished_tag_cleanup_callout: 27,
|
||||
eoa_bronze_plan_banner: 28, # EE-only
|
||||
pipeline_needs_banner: 29
|
||||
pipeline_needs_banner: 29,
|
||||
pipeline_needs_hover_tip: 30
|
||||
}
|
||||
|
||||
validates :user, presence: true
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
- if @broadcast_message.message.present?
|
||||
= render_broadcast_message(@broadcast_message)
|
||||
- else
|
||||
Your message here
|
||||
= _('Your message here')
|
||||
.d-flex.justify-content-center
|
||||
.broadcast-message.broadcast-notification-message.preview.js-broadcast-notification-message-preview.mt-2{ class: ('hidden' unless @broadcast_message.notification? ) }
|
||||
= sprite_icon('bullhorn', css_class: 'vertical-align-text-top')
|
||||
|
@ -12,7 +12,7 @@
|
|||
- if @broadcast_message.message.present?
|
||||
= render_broadcast_message(@broadcast_message)
|
||||
- else
|
||||
Your message here
|
||||
= _('Your message here')
|
||||
|
||||
= form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form js-quick-submit js-requires-input'} do |f|
|
||||
= form_errors(@broadcast_message)
|
||||
|
@ -55,7 +55,7 @@
|
|||
= _('Allow users to dismiss the broadcast message')
|
||||
.form-group.row.js-toggle-colors-container.toggle-colors.hide
|
||||
.col-sm-2.col-form-label
|
||||
= f.label :font, "Font Color"
|
||||
= f.label :font, _("Font Color")
|
||||
.col-sm-10
|
||||
= f.color_field :font, class: "form-control gl-form-input text-font-color"
|
||||
.form-group.row
|
||||
|
@ -77,6 +77,6 @@
|
|||
= f.datetime_select :ends_at, {}, class: 'form-control form-control-inline'
|
||||
.form-actions
|
||||
- if @broadcast_message.persisted?
|
||||
= f.submit "Update broadcast message", class: "btn gl-button btn-confirm"
|
||||
= f.submit _("Update broadcast message"), class: "btn gl-button btn-confirm"
|
||||
- else
|
||||
= f.submit "Add broadcast message", class: "btn gl-button btn-confirm"
|
||||
= f.submit _("Add broadcast message"), class: "btn gl-button btn-confirm"
|
||||
|
|
|
@ -83,5 +83,7 @@
|
|||
#js-tab-tests.tab-pane
|
||||
#js-pipeline-tests-detail{ data: { summary_endpoint: summary_project_pipeline_tests_path(@project, @pipeline, format: :json),
|
||||
suite_endpoint: project_pipeline_test_path(@project, @pipeline, suite_name: 'suite', format: :json),
|
||||
blob_path: project_blob_path(@project, @pipeline.sha) } }
|
||||
blob_path: project_blob_path(@project, @pipeline.sha),
|
||||
has_test_report: @pipeline.has_reports?(Ci::JobArtifact.test_reports).to_s,
|
||||
empty_state_image_path: image_path('illustrations/empty-state/empty-test-cases-lg.svg') } }
|
||||
= render_if_exists "projects/pipelines/tabs_content", pipeline: @pipeline, project: @project
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add link to documentation in empty pipeline test reports
|
||||
merge_request: 59812
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove the enabled by default feature flag for maven group level improvements
|
||||
merge_request: 59748
|
||||
author:
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Externalize strings in broadcast_messages/_form.html.haml
|
||||
merge_request: 58143
|
||||
author: nuwe1
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add cascading namespace setting database migration helper
|
||||
merge_request: 58940
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix EmptyLineAfterFinalLetItBe offenses in spec/models/wiki_page
|
||||
merge_request: 58388
|
||||
author: Huzaifa Iftikhar @huzaifaiftikhar
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Review UI text and docs - Google Chat
|
||||
merge_request: 59518
|
||||
author:
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Review UI text and docs for Flowdock integration
|
||||
merge_request: 59388
|
||||
author:
|
||||
type: other
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: maven_packages_group_level_improvements
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57600
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326099
|
||||
milestone: '13.11'
|
||||
type: development
|
||||
group: group::package
|
||||
default_enabled: true
|
|
@ -0,0 +1,117 @@
|
|||
- title: GitLab Kubernetes Agent available on GitLab.com
|
||||
body: |
|
||||
The GitLab Kubernetes Agent is finally available on GitLab.com. By using the Agent, you can benefit from fast, pull-based deployments to your cluster, while GitLab.com manages the necessary server-side components of the Agent. The GitLab Kubernetes Agent is the core building block of GitLab's Kubernetes integrations. The Agent-based integration today supports pull-based deployments and Network Security policy integration and alerts, and will soon receive support for push-based deployments too.
|
||||
|
||||
Unlike the legacy, certificate-based Kubernetes integration, the GitLab Kubernetes Agent does not require opening up your cluster towards GitLab and allows fine-tuned RBAC controls around GitLab's capabilities within your clusters.
|
||||
stage: Configure
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: [Premium, Ultimate]
|
||||
url: https://docs.gitlab.com/ee/user/clusters/agent/
|
||||
image_url: https://img.youtube.com/vi/4Sh5bghbAjY/hqdefault.jpg
|
||||
published_at: 2021-04-22
|
||||
release: 13.11
|
||||
- title: Compliance pipeline configurations
|
||||
body: |
|
||||
We are thrilled to announce that it is now possible to define enforceable pipelines that will run for any project assigned a corresponding [compliance framework](https://docs.gitlab.com/ee/user/project/settings/#compliance-framework).
|
||||
|
||||
For teams looking to implement compliance requirements in the pipeline workflow, they can now enforce even more separation of duties by setting up a single pipeline definition for a specific compliance framework. All projects using that framework will include the predefined pipeline automatically. Users extend, but cannot modify, the pipeline configuration in the downstream projects, ensuring that compliance steps are run the same way every time.
|
||||
|
||||
This saves security and compliance teams time by eliminating the need to manually copy a pipeline configuration to every project that needs it and then monitoring to prevent edits or removal. It also helps development teams follow policies without requiring them to become experts in compliance.
|
||||
|
||||
Check out the [video walkthrough](https://www.youtube.com/embed/upLJ_equomw) to see its setup and implementation!
|
||||
stage: Manage
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: [Ultimate]
|
||||
url: https://docs.gitlab.com/ee/user/project/settings/#compliance-pipeline-configuration
|
||||
image_url: https://img.youtube.com/vi/upLJ_equomw/hqdefault.jpg
|
||||
published_at: 2021-04-22
|
||||
release: 13.11
|
||||
- title: On-call schedule management
|
||||
body: |
|
||||
Software services do not get "turned off" at the end of the business day. Your customers expect 24/7 availability. When things go wrong, you need a team (or multiple teams!) that can quickly and effectively respond to service outages.
|
||||
|
||||
Being on-call can be a stressful job. To better manage stress and burn-out, most teams rotate this on-call responsibility. GitLab's **on-call schedule management** allows you and your team to create and manage schedules for on-call responsibilities. Alerts received in GitLab through an HTTP endpoint are routed to the on-call engineer in the schedule for that specific project.
|
||||
stage: Monitor
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: [Premium, Ultimate]
|
||||
url: https://docs.gitlab.com/ee/operations/incident_management/oncall_schedules.html
|
||||
image_url: https://img.youtube.com/vi/QXfCQ24-Ufo/hqdefault.jpg
|
||||
published_at: 2021-04-22
|
||||
release: 13.11
|
||||
- title: Use multiple caches in the same job
|
||||
body: |
|
||||
GitLab CI/CD provides a caching mechanism that saves precious development time when your jobs are running. Previously, it was impossible to configure multiple cache keys in the same job. This limitation may have caused you to use artifacts for caching, or use duplicate jobs with different cache paths. In this release, we provide the ability to configure multiple cache keys in a single job which will help you increase your pipeline performance.
|
||||
stage: Verify
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: [Free, Premium, Ultimate]
|
||||
url: https://docs.gitlab.com/ee/ci/yaml/README.html#multiple-caches
|
||||
image_url: https://about.gitlab.com/images/13_11/cache.png
|
||||
published_at: 2021-04-22
|
||||
release: 13.11
|
||||
- title: Group SAML Enforcement for Git activity
|
||||
body: |
|
||||
GitLab group maintainers can now enhance their group security by enforcing Group SAML for Git activity. Security-minded organizations want all GitLab activity to be protected and governed by their SAML Identity Provider. Currently, SAML SSO enforcement only applies to activity in the GitLab UI. Git CLI operations do not require an active SAML SSO session. When Git Group SAML SSO enforcement is enabled, users must have an active web SAML session to perform Git operations in the CLI.
|
||||
stage: Manage
|
||||
self-managed: false
|
||||
gitlab-com: true
|
||||
packages: [Premium, Ultimate]
|
||||
url: https://docs.gitlab.com/ee/user/group/saml_sso/#sso-enforcement
|
||||
image_url: https://about.gitlab.com/images/sdlc-icons/manage.svg
|
||||
published_at: 2021-04-22
|
||||
release: 13.11
|
||||
- title: Cherry pick commits from fork to parent
|
||||
body: |
|
||||
With GitLab 13.11, if you are a project member, you can now cherry-pick commits from downstream forks back into your project. We've added a new **Pick into project** section to the cherry-pick dialog, shown when you select **Options > Cherry-pick** on a commit's details page.
|
||||
|
||||
Your community of contributors can contribute to your project, and your team no longer needs to manually download a fork's `.patch` file to pull in good changes from stale or unmaintained forks.
|
||||
|
||||
Future enhancements include [cherry-picking commits from fork to fork](https://gitlab.com/gitlab-org/gitlab/-/issues/326771).
|
||||
stage: Create
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: [Free, Premium, Ultimate]
|
||||
url: https://docs.gitlab.com/ee/user/project/merge_requests/cherry_pick_changes.html#cherry-pick-into-a-project
|
||||
image_url: https://about.gitlab.com/images/13_11/cherry_pick_commits_from_fork_to_parent.png
|
||||
published_at: 2021-04-22
|
||||
release: 13.11
|
||||
- title: Improvements to Jira Connect application configuration
|
||||
body: |
|
||||
When configuring the [GitLab.com for Jira](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud) application, you can now filter the available namespaces when linking them to your account, simplifying configuration for users with access to a large number of namespaces.
|
||||
stage: Create
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: [Free, Premium, Ultimate]
|
||||
url: https://docs.gitlab.com/ee/integration/jira/connect-app.html
|
||||
image_url: https://about.gitlab.com/images/13_11/jira-connect-app-search.png
|
||||
published_at: 2021-04-22
|
||||
release: 13.11
|
||||
- title: Search within a settings page
|
||||
body: |
|
||||
Finding the exact location of a GitLab setting can be challenging. Even if you know generally where to look, many of the settings views have multiple sections and dozens of individual configuration options.
|
||||
|
||||
In this release, you can now use the search field in group, project, admin, and user settings to quickly pinpoint your desired configuration. Your search criteria will filter the current page down to display only relevant settings and even highlight occurrences of your search term on the page.
|
||||
|
||||
In the future iterations, we are looking to extend this functionality to [search across all settings views](https://gitlab.com/groups/gitlab-org/-/epics/5198).
|
||||
stage: Create
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: [Free, Premium, Ultimate]
|
||||
url: https://docs.gitlab.com/ee/user/search/#search-settings
|
||||
image_url: https://about.gitlab.com/images/13_11/search-settings.gif
|
||||
published_at: 2021-04-22
|
||||
release: 13.11
|
||||
- title: Deploy GitLab on OpenShift and Kubernetes with the GitLab Operator (beta)
|
||||
body: |
|
||||
GitLab is working to offer full support for OpenShift. To accomplish this, we have released the MVP [GitLab Operator](https://gitlab.com/gitlab-org/gl-openshift/gitlab-operator/-/tree/master/doc). The operator aims to manage the full lifecycle of GitLab instances on Kubernetes and OpenShift container platforms. Currently, this is a [beta release](https://gitlab.com/groups/gitlab-org/-/epics/3444) and it is **not recommended for production use**. The next steps will be to make the operator generally available (GA). In the future the operator will become the recommended installation method for Kubernetes and OpenShift, although the GitLab Helm chart will still be supported. We welcome you to try this operator and [provide feedback on our issue tracker](https://gitlab.com/gitlab-org/gl-openshift/gitlab-operator/-/issues/131).
|
||||
stage: Enablement
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: [Free, Premium, Ultimate]
|
||||
url: https://gitlab.com/gitlab-org/gl-openshift/gitlab-operator/-/tree/master/doc
|
||||
image_url: https://about.gitlab.com/images/13_11/gitlab-operator.png
|
||||
published_at: 2021-04-22
|
||||
release: 13.11
|
|
@ -1,237 +1,8 @@
|
|||
---
|
||||
stage: Create
|
||||
group: Source Code
|
||||
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments"
|
||||
type: reference, howto
|
||||
disqus_identifier: 'https://docs.gitlab.com/ee/workflow/git_annex.html'
|
||||
redirect_to: 'index.md'
|
||||
---
|
||||
|
||||
# Git annex
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
WARNING:
|
||||
[Git Annex support was removed](https://gitlab.com/gitlab-org/gitlab/-/issues/1648)
|
||||
in GitLab 9.0. Read through the [migration guide from git-annex to Git LFS](../topics/git/lfs/migrate_from_git_annex_to_git_lfs.md).
|
||||
|
||||
The biggest limitation of Git, compared to some older centralized version
|
||||
control systems has been the maximum size of the repositories.
|
||||
|
||||
The general recommendation is to not have Git repositories larger than 1GB to
|
||||
preserve performance. Although GitLab has no limit (some repositories in GitLab
|
||||
are over 50GB!), we subscribe to the advice to keep repositories as small as
|
||||
you can.
|
||||
|
||||
Not being able to version control large binaries is a big problem for many
|
||||
larger organizations.
|
||||
Videos, photos, audio, compiled binaries, and many other types of files are too
|
||||
large. As a workaround, people keep artwork-in-progress in a Dropbox folder and
|
||||
only check in the final result. This results in using outdated files, not
|
||||
having a complete history, and increases the risk of losing work.
|
||||
|
||||
This problem is solved in GitLab Enterprise Edition by integrating the
|
||||
[git-annex](https://git-annex.branchable.com/) application.
|
||||
|
||||
`git-annex` allows managing large binaries with Git without checking the
|
||||
contents into Git.
|
||||
You check-in only a symlink that contains the SHA-1 of the large binary. If you
|
||||
need the large binary, you can sync it from the GitLab server over `rsync`, a
|
||||
very fast file copying tool.
|
||||
|
||||
## GitLab git-annex Configuration
|
||||
|
||||
`git-annex` is disabled by default in GitLab. Below are the
|
||||
configuration options required to enable it.
|
||||
|
||||
### Requirements
|
||||
|
||||
`git-annex` needs to be installed both on the server and the client-side.
|
||||
|
||||
For Debian-like systems (for example, Debian and Ubuntu) this can be achieved by running:
|
||||
|
||||
```shell
|
||||
sudo apt-get update && sudo apt-get install git-annex
|
||||
```
|
||||
|
||||
For RedHat-like systems (for example, CentOS and RHEL) this can be achieved by running:
|
||||
|
||||
```shell
|
||||
sudo yum install epel-release && sudo yum install git-annex
|
||||
```
|
||||
|
||||
### Configuration for Omnibus packages
|
||||
|
||||
For Omnibus GitLab packages, only one configuration setting is needed.
|
||||
The Omnibus package internally sets the correct options in all locations.
|
||||
|
||||
1. In `/etc/gitlab/gitlab.rb` add the following line:
|
||||
|
||||
```ruby
|
||||
gitlab_shell['git_annex_enabled'] = true
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
|
||||
|
||||
### Configuration for installations from source
|
||||
|
||||
There are 2 settings to enable git-annex on your GitLab server.
|
||||
|
||||
One is located in `config/gitlab.yml` of the GitLab repository and the other
|
||||
one is located in `config.yml` of GitLab Shell.
|
||||
|
||||
1. In `config/gitlab.yml` add or edit the following lines:
|
||||
|
||||
```yaml
|
||||
gitlab_shell:
|
||||
git_annex_enabled: true
|
||||
```
|
||||
|
||||
1. In `config.yml` of GitLab Shell add or edit the following lines:
|
||||
|
||||
```yaml
|
||||
git_annex_enabled: true
|
||||
```
|
||||
|
||||
1. Save the files and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect.
|
||||
|
||||
## Using GitLab git-annex
|
||||
|
||||
NOTE:
|
||||
Your Git remotes must be using the SSH protocol, not HTTP(S).
|
||||
|
||||
Here is an example workflow of uploading a very large file and then checking it
|
||||
into your Git repository:
|
||||
|
||||
```shell
|
||||
git clone git@example.com:group/project.git
|
||||
|
||||
git annex init 'My Laptop' # initialize the annex project and give an optional description
|
||||
cp ~/tmp/debian.iso ./ # copy a large file into the current directory
|
||||
git annex add debian.iso # add the large file to git annex
|
||||
git commit -am "Add Debian iso" # commit the file metadata
|
||||
git annex sync --content # sync the Git repo and large file to the GitLab server
|
||||
```
|
||||
|
||||
The output should look like this:
|
||||
|
||||
```plaintext
|
||||
commit
|
||||
On branch master
|
||||
Your branch is ahead of 'origin/master' by 1 commit.
|
||||
(use "git push" to publish your local commits)
|
||||
nothing to commit, working tree clean
|
||||
ok
|
||||
pull origin
|
||||
remote: Counting objects: 5, done.
|
||||
remote: Compressing objects: 100% (4/4), done.
|
||||
remote: Total 5 (delta 2), reused 0 (delta 0)
|
||||
Unpacking objects: 100% (5/5), done.
|
||||
From example.com:group/project
|
||||
497842b..5162f80 git-annex -> origin/git-annex
|
||||
ok
|
||||
(merging origin/git-annex into git-annex...)
|
||||
(recording state in git...)
|
||||
copy debian.iso (checking origin...) (to origin...)
|
||||
SHA256E-s26214400--8092b3d482fb1b7a5cf28c43bc1425c8f2d380e86869c0686c49aa7b0f086ab2.iso
|
||||
26,214,400 100% 638.88kB/s 0:00:40 (xfr#1, to-chk=0/1)
|
||||
ok
|
||||
pull origin
|
||||
ok
|
||||
(recording state in git...)
|
||||
push origin
|
||||
Counting objects: 15, done.
|
||||
Delta compression using up to 4 threads.
|
||||
Compressing objects: 100% (13/13), done.
|
||||
Writing objects: 100% (15/15), 1.64 KiB | 0 bytes/s, done.
|
||||
Total 15 (delta 1), reused 0 (delta 0)
|
||||
To example.com:group/project.git
|
||||
* [new branch] git-annex -> synced/git-annex
|
||||
* [new branch] master -> synced/master
|
||||
ok
|
||||
```
|
||||
|
||||
Your files can be found in the `master` branch, but more branches are created
|
||||
by the `annex sync` command.
|
||||
|
||||
Git Annex creates a new directory at `.git/annex/` and records the
|
||||
tracked files in the `.git/config` file. The files you assign to be tracked
|
||||
with `git-annex` don't affect the existing `.git/config` records. The files
|
||||
are turned into symbolic links that point to data in `.git/annex/objects/`.
|
||||
|
||||
The `debian.iso` file in the example contain the symbolic link:
|
||||
|
||||
```plaintext
|
||||
.git/annex/objects/ZW/1k/SHA256E-s82701--6384039733b5035b559efd5a2e25a493ab6e09aabfd5162cc03f6f0ec238429d.png/SHA256E-s82701--6384039733b5035b559efd5a2e25a493ab6e09aabfd5162cc03f6f0ec238429d.iso
|
||||
```
|
||||
|
||||
Use `git annex info` to retrieve the information about the local copy of your
|
||||
repository.
|
||||
|
||||
---
|
||||
|
||||
You can download a single large file with these commands:
|
||||
|
||||
```shell
|
||||
git clone git@gitlab.example.com:group/project.git
|
||||
|
||||
git annex sync # sync Git branches but not the large file
|
||||
git annex get debian.iso # download the large file
|
||||
```
|
||||
|
||||
To download all files:
|
||||
|
||||
```shell
|
||||
git clone git@gitlab.example.com:group/project.git
|
||||
|
||||
git annex sync --content # sync Git branches and download all the large files
|
||||
```
|
||||
|
||||
By using `git-annex` without GitLab, anyone that can access the server can also
|
||||
access the files of all projects. GitLab Annex ensures that you can only
|
||||
access files of projects you have access to (developer, maintainer, or owner role).
|
||||
|
||||
## How it works
|
||||
|
||||
Internally GitLab uses [GitLab Shell](https://gitlab.com/gitlab-org/gitlab-shell) to handle SSH access and this was a great
|
||||
integration point for `git-annex`.
|
||||
There is a setting in GitLab Shell so you can disable GitLab Annex support
|
||||
if you want to.
|
||||
|
||||
## Troubleshooting tips
|
||||
|
||||
Differences in the version of `git-annex` on the GitLab server and on local machines
|
||||
can cause `git-annex` to raise unpredicted warnings and errors.
|
||||
|
||||
Consult the [Annex upgrade page](https://git-annex.branchable.com/upgrades/) for more information about
|
||||
the differences between versions. You can find out which version is installed
|
||||
on your server by navigating to `https://pkgs.org/download/git-annex` and
|
||||
searching for your distribution.
|
||||
|
||||
Although there is no general guide for `git-annex` errors, there are a few tips
|
||||
on how to go around the warnings.
|
||||
|
||||
### `git-annex-shell: Not a git-annex or gcrypt repository`
|
||||
|
||||
This warning can appear on the initial `git annex sync --content` and is caused
|
||||
by differences in `git-annex-shell`. You can read more about it
|
||||
[in this git-annex issue](https://git-annex.branchable.com/forum/Error_from_git-annex-shell_on_creation_of_gcrypt_special_remote/).
|
||||
|
||||
One important thing to note is that despite the warning, the `sync` succeeds
|
||||
and the files are pushed to the GitLab repository.
|
||||
|
||||
If you get hit by this, you can run the following command inside the repository
|
||||
that the warning was raised:
|
||||
|
||||
```shell
|
||||
git config remote.origin.annex-ignore false
|
||||
```
|
||||
|
||||
Consecutive runs of `git annex sync --content` **should not** produce this
|
||||
warning and the output should look like this:
|
||||
|
||||
```plaintext
|
||||
commit ok
|
||||
pull origin
|
||||
ok
|
||||
pull origin
|
||||
ok
|
||||
push origin
|
||||
```
|
||||
<!-- This redirect file can be deleted after <2021-07-22>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||
|
|
|
@ -190,7 +190,6 @@ Learn how to install, configure, update, and maintain your GitLab instance.
|
|||
- [Git LFS configuration](lfs/index.md): Learn how to configure LFS for GitLab.
|
||||
- [Housekeeping](housekeeping.md): Keep your Git repositories tidy and fast.
|
||||
- [Configuring Git Protocol v2](git_protocol.md): Git protocol version 2 support.
|
||||
- [Manage large files with `git-annex` (Deprecated)](git_annex.md)
|
||||
|
||||
## Monitoring GitLab
|
||||
|
||||
|
|
|
@ -13783,6 +13783,7 @@ Name of the feature that the callout is for.
|
|||
| <a id="usercalloutfeaturenameenumnew_user_signups_cap_reached"></a>`NEW_USER_SIGNUPS_CAP_REACHED` | Callout feature name for new_user_signups_cap_reached. |
|
||||
| <a id="usercalloutfeaturenameenumpersonal_access_token_expiry"></a>`PERSONAL_ACCESS_TOKEN_EXPIRY` | Callout feature name for personal_access_token_expiry. |
|
||||
| <a id="usercalloutfeaturenameenumpipeline_needs_banner"></a>`PIPELINE_NEEDS_BANNER` | Callout feature name for pipeline_needs_banner. |
|
||||
| <a id="usercalloutfeaturenameenumpipeline_needs_hover_tip"></a>`PIPELINE_NEEDS_HOVER_TIP` | Callout feature name for pipeline_needs_hover_tip. |
|
||||
| <a id="usercalloutfeaturenameenumregistration_enabled_callout"></a>`REGISTRATION_ENABLED_CALLOUT` | Callout feature name for registration_enabled_callout. |
|
||||
| <a id="usercalloutfeaturenameenumservice_templates_deprecated_callout"></a>`SERVICE_TEMPLATES_DEPRECATED_CALLOUT` | Callout feature name for service_templates_deprecated_callout. |
|
||||
| <a id="usercalloutfeaturenameenumsuggest_pipeline"></a>`SUGGEST_PIPELINE` | Callout feature name for suggest_pipeline. |
|
||||
|
@ -14653,7 +14654,7 @@ Field that are available while modifying the custom mapping attributes for an HT
|
|||
| <a id="boardissueinputlabelname"></a>`labelName` | [`[String]`](#string) | Filter by label name. |
|
||||
| <a id="boardissueinputmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Filter by milestone title. |
|
||||
| <a id="boardissueinputmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by reaction emoji applied by the current user. |
|
||||
| <a id="boardissueinputnot"></a>`not` | [`NegatedBoardIssueInput`](#negatedboardissueinput) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
|
||||
| <a id="boardissueinputnot"></a>`not` | [`NegatedBoardIssueInput`](#negatedboardissueinput) | List of negated arguments. |
|
||||
| <a id="boardissueinputreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
|
||||
| <a id="boardissueinputsearch"></a>`search` | [`String`](#string) | Search query for issue title or description. |
|
||||
| <a id="boardissueinputweight"></a>`weight` | [`String`](#string) | Filter by weight. |
|
||||
|
@ -14745,7 +14746,7 @@ Input type for DastSiteProfile authentication.
|
|||
| <a id="epicfiltersauthorusername"></a>`authorUsername` | [`String`](#string) | Filter by author username. |
|
||||
| <a id="epicfilterslabelname"></a>`labelName` | [`[String]`](#string) | Filter by label name. |
|
||||
| <a id="epicfiltersmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by reaction emoji applied by the current user. |
|
||||
| <a id="epicfiltersnot"></a>`not` | [`NegatedEpicBoardIssueInput`](#negatedepicboardissueinput) | Negated epic arguments. Warning: this argument is experimental and a subject to change in the future. |
|
||||
| <a id="epicfiltersnot"></a>`not` | [`NegatedEpicBoardIssueInput`](#negatedepicboardissueinput) | Negated epic arguments. |
|
||||
| <a id="epicfilterssearch"></a>`search` | [`String`](#string) | Search query for epic title or description. |
|
||||
|
||||
### `EpicTreeNodeFieldsInputType`
|
||||
|
|
|
@ -572,7 +572,9 @@ GET /projects/:id/services/external-wiki
|
|||
|
||||
## Flowdock
|
||||
|
||||
Flowdock is a collaboration web app for technical teams.
|
||||
Flowdock is a ChatOps application for collaboration in software engineering
|
||||
companies. You can send notifications from GitLab events to Flowdock flows.
|
||||
For integration instructions, see the [Flowdock documentation](https://www.flowdock.com/help/gitlab).
|
||||
|
||||
### Create/Edit Flowdock service
|
||||
|
||||
|
|
|
@ -207,6 +207,7 @@ In these cases, use the following workflow:
|
|||
- [Newlines style guide](newlines_styleguide.md)
|
||||
- [Image scaling guide](image_scaling.md)
|
||||
- [Export to CSV](export_csv.md)
|
||||
- [Cascading Settings](cascading_settings.md)
|
||||
|
||||
## Performance guides
|
||||
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Access
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Cascading Settings
|
||||
|
||||
> Introduced in [GitLab 13.11](https://gitlab.com/gitlab-org/gitlab/-/issues/321724).
|
||||
|
||||
The cascading settings framework allows groups to essentially inherit settings
|
||||
values from ancestors (parent group on up the group hierarchy) and from
|
||||
instance-level application settings. The framework also allows settings values
|
||||
to be enforced on groups lower in the hierarchy.
|
||||
|
||||
Cascading settings can currently only be defined within `NamespaceSetting`, though
|
||||
the framework may be extended to other objects in the future.
|
||||
|
||||
## Add a new cascading setting
|
||||
|
||||
Settings are not cascading by default. To define a cascading setting, take the following steps:
|
||||
|
||||
1. In the `NamespaceSetting` model, define the new attribute using the `cascading_attr`
|
||||
helper method. You can use an array to define multiple attributes on a single line.
|
||||
|
||||
```ruby
|
||||
class NamespaceSetting
|
||||
include CascadingNamespaceSettingAttribute
|
||||
|
||||
cascading_attr :delayed_project_removal
|
||||
end
|
||||
```
|
||||
|
||||
1. Create the database columns.
|
||||
|
||||
You can use the following database migration helper for a completely new setting.
|
||||
The helper creates four columns, two each in `namespace_settings` and
|
||||
`application_settings`.
|
||||
|
||||
```ruby
|
||||
class AddDelayedProjectRemovalCascadingSetting < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings
|
||||
|
||||
def up
|
||||
add_cascading_namespace_setting :delayed_project_removal, :boolean, default: false, null: false
|
||||
end
|
||||
|
||||
def down
|
||||
remove_cascading_namespace_setting :delayed_project_removal
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Existing settings being converted to a cascading setting will require individual
|
||||
migrations to add columns and change existing columns. Use the specifications
|
||||
below to create migrations as required:
|
||||
|
||||
1. Columns in `namespace_settings` table:
|
||||
- `delayed_project_removal`: No default value. Null values allowed. Use any column type.
|
||||
- `lock_delayed_project_removal`: Boolean column. Default value is false. Null values not allowed.
|
||||
1. Columns in `application_settings` table:
|
||||
- `delayed_project_removal`: Type matching for the column created in `namespace_settings`.
|
||||
Set default value as desired. Null values not allowed.
|
||||
- `lock_delayed_project_removal`: Boolean column. Default value is false. Null values not allowed.
|
||||
|
||||
## Convenience methods
|
||||
|
||||
By defining an attribute using the `cascading_attr` method, a number of convenience
|
||||
methods are automatically defined.
|
||||
|
||||
**Definition:**
|
||||
|
||||
```ruby
|
||||
cascading_attr :delayed_project_removal
|
||||
```
|
||||
|
||||
**Convenience Methods Available:**
|
||||
|
||||
- `delayed_project_removal`
|
||||
- `delayed_project_removal=`
|
||||
- `delayed_project_removal_locked?`
|
||||
- `delayed_project_removal_locked_by_ancestor?`
|
||||
- `delayed_project_removal_locked_by_application_setting?`
|
||||
- `delayed_project_removal?` (Boolean attributes only)
|
||||
- `delayed_project_removal_locked_ancestor` - (Returns locked namespace settings object [namespace_id])
|
||||
|
||||
The attribute reader method (`delayed_project_removal`) returns the correct
|
||||
cascaded value using the following criteria:
|
||||
|
||||
1. Returns the dirty value, if the attribute has changed. This allows standard
|
||||
Rails validators to be used on the attribute, though `nil` values *must* be allowed.
|
||||
1. Return locked ancestor value.
|
||||
1. Return locked instance-level application settings value.
|
||||
1. Return this namespace's attribute, if not nil.
|
||||
1. Return value from nearest ancestor where value is not nil.
|
||||
1. Return instance-level application setting.
|
|
@ -48,6 +48,12 @@ For all of the above, please include `--why "Reason"` and `--who "My Name"` so t
|
|||
|
||||
More detailed information on how the gem and its commands work is available in the [License Finder README](https://github.com/pivotal/LicenseFinder).
|
||||
|
||||
## Encryption keys
|
||||
|
||||
If your license was created in your local development or staging environment for Customers Portal or License App, an environment variable called `GITLAB_LICENSE_MODE` with the value `test` needs to be set to use the correct decryption key.
|
||||
|
||||
Those projects are set to use a test license encryption key by default.
|
||||
|
||||
## Additional information
|
||||
|
||||
Please see the [Open Source](https://about.gitlab.com/handbook/engineering/open-source/#using-open-source-libraries) page for more information on licensing.
|
||||
|
|
|
@ -492,39 +492,32 @@ Implemented using Redis methods [PFADD](https://redis.io/commands/pfadd) and [PF
|
|||
Example event:
|
||||
|
||||
```yaml
|
||||
- name: i_compliance_credential_inventory
|
||||
category: compliance
|
||||
redis_slot: compliance
|
||||
expiry: 42 # 6 weeks
|
||||
- name: users_creating_epics
|
||||
category: epics_usage
|
||||
redis_slot: users
|
||||
aggregation: weekly
|
||||
feature_flag: usage_data_i_compliance_credential_inventory
|
||||
feature_flag: track_epics_activity
|
||||
```
|
||||
|
||||
Keys:
|
||||
|
||||
- `name`: unique event name.
|
||||
|
||||
Name format `<prefix>_<redis_slot>_name`.
|
||||
Name format for Redis HLL events `<name>_<redis_slot>`.
|
||||
|
||||
Use one of the following prefixes for the event's name:
|
||||
|
||||
- `g_` for group, as an event which is tracked for group.
|
||||
- `p_` for project, as an event which is tracked for project.
|
||||
- `i_` for instance, as an event which is tracked for instance.
|
||||
- `a_` for events encompassing all `g_`, `p_`, `i_`.
|
||||
- `o_` for other.
|
||||
[See Metric name](metrics_dictionary.md#metric-name) for a complete guide on metric naming suggestion.
|
||||
|
||||
Consider including in the event's name the Redis slot to be able to count totals for a specific category.
|
||||
|
||||
Example names: `i_compliance_credential_inventory`, `g_analytics_contribution`.
|
||||
Example names: `users_creating_epics`, `users_triggering_security_scans`.
|
||||
|
||||
- `category`: event category. Used for getting total counts for events in a category, for easier
|
||||
access to a group of events.
|
||||
- `redis_slot`: optional Redis slot; default value: event name. Used if needed to calculate totals
|
||||
for a group of metrics. Ensure keys are in the same slot. For example:
|
||||
`i_compliance_credential_inventory` with `redis_slot: 'compliance'` builds Redis key
|
||||
`i_{compliance}_credential_inventory-2020-34`. If `redis_slot` is not defined the Redis key will
|
||||
be `{i_compliance_credential_inventory}-2020-34`.
|
||||
`users_creating_epics` with `redis_slot: 'users'` builds Redis key
|
||||
`{users}_creating_epics-2020-34`. If `redis_slot` is not defined the Redis key will
|
||||
be `{users_creating_epics}-2020-34`.
|
||||
- `expiry`: expiry time in days. Default: 29 days for daily aggregation and 6 weeks for weekly
|
||||
aggregation.
|
||||
- `aggregation`: may be set to a `:daily` or `:weekly` key. Defines how counting data is stored in Redis.
|
||||
|
@ -581,7 +574,7 @@ Use one of the following methods to track events:
|
|||
user: current_user, subject: user_group
|
||||
).execute
|
||||
|
||||
increment_unique_values('i_list_repositories', current_user.id)
|
||||
increment_unique_values('users_listing_repositories', current_user.id)
|
||||
|
||||
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
|
||||
end
|
||||
|
@ -655,15 +648,15 @@ Use one of the following methods to track events:
|
|||
Trigger events in rails console by using `track_event` method
|
||||
|
||||
```ruby
|
||||
Gitlab::UsageDataCounters::HLLRedisCounter.track_event('g_compliance_audit_events', values: 1)
|
||||
Gitlab::UsageDataCounters::HLLRedisCounter.track_event('g_compliance_audit_events', values: [2, 3])
|
||||
Gitlab::UsageDataCounters::HLLRedisCounter.track_event('users_viewing_compliance_audit_events', values: 1)
|
||||
Gitlab::UsageDataCounters::HLLRedisCounter.track_event('users_viewing_compliance_audit_events', values: [2, 3])
|
||||
```
|
||||
|
||||
Next, get the unique events for the current week.
|
||||
|
||||
```ruby
|
||||
# Get unique events for metric for current_week
|
||||
Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: 'g_compliance_audit_events',
|
||||
Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: 'users_viewing_compliance_audit_events',
|
||||
start_date: Date.current.beginning_of_week, end_date: Date.current.next_week)
|
||||
```
|
||||
|
||||
|
@ -824,7 +817,6 @@ We return fallback values in these cases:
|
|||
|
||||
Add the metric in one of the top level keys
|
||||
|
||||
- `license`: for license related metrics.
|
||||
- `settings`: for settings related metrics.
|
||||
- `counts_weekly`: for counters that have data for the most recent 7 days.
|
||||
- `counts_monthly`: for counters that have data for the most recent 28 days.
|
||||
|
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 29 KiB |
|
@ -101,5 +101,4 @@ The following relate to Git Large File Storage:
|
|||
- [Removing objects from LFS](lfs/index.md#removing-objects-from-lfs)
|
||||
- [GitLab Git LFS user documentation](lfs/index.md)
|
||||
- [GitLab Git LFS admin documentation](../../administration/lfs/index.md)
|
||||
- [Git Annex to Git LFS migration guide](lfs/migrate_from_git_annex_to_git_lfs.md)
|
||||
- [Towards a production quality open source Git LFS server](https://about.gitlab.com/blog/2015/08/13/towards-a-production-quality-open-source-git-lfs-server/)
|
||||
|
|
|
@ -1,248 +1,8 @@
|
|||
---
|
||||
stage: Create
|
||||
group: Source Code
|
||||
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments"
|
||||
type: reference, howto
|
||||
redirect_to: 'index.md'
|
||||
---
|
||||
|
||||
# Migration guide from Git Annex to Git LFS **(FREE)**
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
WARNING:
|
||||
Git Annex support [has been removed](https://gitlab.com/gitlab-org/gitlab/-/issues/1648) in GitLab Enterprise
|
||||
Edition 9.0 (2017/03/22).
|
||||
|
||||
Both [Git Annex](http://git-annex.branchable.com/) and [Git LFS](https://git-lfs.github.com/) are tools to manage large files in Git.
|
||||
|
||||
## History
|
||||
|
||||
Git Annex [was introduced in GitLab Enterprise Edition 7.8](https://about.gitlab.com/blog/2015/02/17/gitlab-annex-solves-the-problem-of-versioning-large-binaries-with-git/), at a time
|
||||
where Git LFS didn't yet exist. A few months later, GitLab brought support for
|
||||
Git LFS in [GitLab 8.2](https://about.gitlab.com/blog/2015/11/23/announcing-git-lfs-support-in-gitlab/) and is available for both Community and
|
||||
Enterprise editions.
|
||||
|
||||
## Differences between Git Annex and Git LFS
|
||||
|
||||
Some items below are general differences between the two protocols and some are
|
||||
ones that GitLab developed.
|
||||
|
||||
- Git Annex works only through SSH, whereas Git LFS works both with SSH and HTTPS
|
||||
(SSH support was added in GitLab 8.12).
|
||||
- Annex files are stored in a sub-directory of the normal repositories, whereas
|
||||
LFS files are stored outside of the repositories in a place you can define.
|
||||
- Git Annex requires a more complex setup, but has much more options than Git
|
||||
LFS. You can compare the commands each one offers by running `man git-annex`
|
||||
and `man git-lfs`.
|
||||
- Annex files cannot be browsed directly in the GitLab interface, whereas LFS
|
||||
files can.
|
||||
|
||||
## Migration steps
|
||||
|
||||
Git Annex files are stored in a sub-directory of the normal repositories
|
||||
(`.git/annex/objects`) and LFS files are stored outside of the repositories.
|
||||
The two aren't compatible as they are using a different scheme. Therefore, the
|
||||
migration has to be done manually per repository.
|
||||
|
||||
There are basically two steps you need to take in order to migrate from Git
|
||||
Annex to Git LFS.
|
||||
|
||||
### TL; DR
|
||||
|
||||
If you know what you are doing and want to skip the reading, this is what you
|
||||
need to do (we assume you have [git-annex enabled](../../../administration/git_annex.md#using-gitlab-git-annex) in your
|
||||
repository and that you have made backups in case something goes wrong).
|
||||
Fire up a terminal, navigate to your Git repository and:
|
||||
|
||||
1. Disable `git-annex`:
|
||||
|
||||
```shell
|
||||
git annex sync --content
|
||||
git annex direct
|
||||
git annex uninit
|
||||
git annex indirect
|
||||
```
|
||||
|
||||
1. Enable `git-lfs`:
|
||||
|
||||
```shell
|
||||
git lfs install
|
||||
git lfs track <files>
|
||||
git add .
|
||||
git commit -m "commit message"
|
||||
git push
|
||||
```
|
||||
|
||||
### Disabling Git Annex in your repository
|
||||
|
||||
Before changing anything, make sure you have a backup of your repository first.
|
||||
There are a couple of ways to do that, but you can clone it to another
|
||||
local path and maybe push it to GitLab if you want a remote backup as well.
|
||||
A guide on
|
||||
[how to back up a **git-annex** repository to an external hard drive](https://www.thomas-krenn.com/en/wiki/Git-annex_Repository_on_an_External_Hard_Drive) is also available.
|
||||
|
||||
Because Annex files are stored as objects with symlinks and cannot be directly
|
||||
modified, we need to first remove those symlinks.
|
||||
|
||||
NOTE:
|
||||
Make sure the you read about the [`direct` mode](https://git-annex.branchable.com/direct_mode/) as it contains
|
||||
information that may fit in your use case. The `annex direct` command is
|
||||
deprecated in Git Annex version 6, so you may need to upgrade your repository
|
||||
if the server also has Git Annex 6 installed. Read more in the
|
||||
[Git Annex troubleshooting tips](../../../administration/git_annex.md#troubleshooting-tips) section.
|
||||
|
||||
1. Backup your repository
|
||||
|
||||
```shell
|
||||
cd repository
|
||||
git annex sync --content
|
||||
cd ..
|
||||
git clone repository repository-backup
|
||||
cd repository-backup
|
||||
git annex get
|
||||
cd ..
|
||||
```
|
||||
|
||||
1. Use `annex direct`:
|
||||
|
||||
```shell
|
||||
cd repository
|
||||
git annex direct
|
||||
```
|
||||
|
||||
The output should be similar to this:
|
||||
|
||||
```shell
|
||||
commit
|
||||
On branch master
|
||||
Your branch is up-to-date with 'origin/master'.
|
||||
nothing to commit, working tree clean
|
||||
ok
|
||||
direct debian.iso ok
|
||||
direct ok
|
||||
```
|
||||
|
||||
1. Disable Git Annex with [`annex uninit`](https://git-annex.branchable.com/git-annex-uninit/):
|
||||
|
||||
```shell
|
||||
git annex uninit
|
||||
```
|
||||
|
||||
The output should be similar to this:
|
||||
|
||||
```shell
|
||||
unannex debian.iso ok
|
||||
Deleted branch git-annex (was 2534d2c).
|
||||
```
|
||||
|
||||
This command runs `unannex` on every file in the repository, leaving the original files.
|
||||
|
||||
1. Switch back to `indirect` mode:
|
||||
|
||||
```shell
|
||||
git annex indirect
|
||||
```
|
||||
|
||||
The output should be similar to this:
|
||||
|
||||
```shell
|
||||
(merging origin/git-annex into git-annex...)
|
||||
(recording state in git...)
|
||||
commit (recording state in git...)
|
||||
|
||||
ok
|
||||
(recording state in git...)
|
||||
[master fac3194] commit before switching to indirect mode
|
||||
1 file changed, 1 deletion(-)
|
||||
delete mode 120000 alpine-virt-3.4.4-x86_64.iso
|
||||
ok
|
||||
indirect ok
|
||||
ok
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
At this point, you have two options. Either add, commit and push the files
|
||||
directly back to GitLab or switch to Git LFS. The LFS switch is described in
|
||||
the next section.
|
||||
|
||||
### Enabling Git LFS in your repository
|
||||
|
||||
Git LFS is enabled by default on all GitLab products (GitLab CE, GitLab EE,
|
||||
GitLab.com), therefore, you don't need to do anything server-side.
|
||||
|
||||
1. First, make sure you have `git-lfs` installed locally:
|
||||
|
||||
```shell
|
||||
git lfs help
|
||||
```
|
||||
|
||||
If the terminal doesn't prompt you with a full response on `git-lfs` commands,
|
||||
[install the Git LFS client](https://git-lfs.github.com/) first.
|
||||
|
||||
1. Inside the repository, run the following command to initiate LFS:
|
||||
|
||||
```shell
|
||||
git lfs install
|
||||
```
|
||||
|
||||
1. Enable `git-lfs` for the group of files you want to track. You
|
||||
can track specific files, all files containing the same extension, or an
|
||||
entire directory:
|
||||
|
||||
```shell
|
||||
git lfs track images/01.png # per file
|
||||
git lfs track **/*.png # per extension
|
||||
git lfs track images/ # per directory
|
||||
```
|
||||
|
||||
After this, run `git status` to see the `.gitattributes` added
|
||||
to your repository. It collects all file patterns that you chose to track via
|
||||
`git-lfs`.
|
||||
|
||||
1. Add the files, commit and push them to GitLab:
|
||||
|
||||
```shell
|
||||
git add .
|
||||
git commit -m "commit message"
|
||||
git push
|
||||
```
|
||||
|
||||
If your remote is set up with HTTP, you are asked to enter your login
|
||||
credentials. If you have [2FA enabled](../../../user/profile/account/two_factor_authentication.md), make sure to use a
|
||||
[personal access token](../../../user/profile/account/two_factor_authentication.md#personal-access-tokens)
|
||||
instead of your password.
|
||||
|
||||
## Removing the Git Annex branches
|
||||
|
||||
After the migration finishes successfully, you can remove all `git-annex`
|
||||
related branches from your repository.
|
||||
|
||||
On GitLab, navigate to your project's **Repository > Branches** and delete all
|
||||
branches created by Git Annex: `git-annex`, and all under `synced/`.
|
||||
|
||||
![repository branches](img/git-annex-branches.png)
|
||||
|
||||
You can also do this on the command line with:
|
||||
|
||||
```shell
|
||||
git branch -d synced/master
|
||||
git branch -d synced/git-annex
|
||||
git push origin :synced/master
|
||||
git push origin :synced/git-annex
|
||||
git push origin :git-annex
|
||||
git remote prune origin
|
||||
```
|
||||
|
||||
If there are still some Annex objects inside your repository (`.git/annex/`)
|
||||
or references inside `.git/config`, run `annex uninit` again:
|
||||
|
||||
```shell
|
||||
git annex uninit
|
||||
```
|
||||
|
||||
## Further Reading
|
||||
|
||||
- (Blog Post) [Getting Started with Git FLS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
|
||||
- (Blog Post) [Announcing LFS Support in GitLab](https://about.gitlab.com/blog/2015/11/23/announcing-git-lfs-support-in-gitlab/)
|
||||
- (Blog Post) [GitLab Annex Solves the Problem of Versioning Large Binaries with Git](https://about.gitlab.com/blog/2015/02/17/gitlab-annex-solves-the-problem-of-versioning-large-binaries-with-git/)
|
||||
- [Git Annex](../../../administration/git_annex.md)
|
||||
- [Git LFS](index.md)
|
||||
<!-- This redirect file can be deleted after <2021-07-22>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||
|
|
|
@ -174,7 +174,6 @@ but commented out to help encourage others to add to it in the future. -->
|
|||
## References
|
||||
|
||||
- [Getting Started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
|
||||
- [Migrate from Git Annex to Git LFS](migrate_from_git_annex_to_git_lfs.md)
|
||||
- [GitLab Git LFS user documentation](index.md)
|
||||
- [GitLab Git LFS administrator documentation](../../../administration/lfs/index.md)
|
||||
- Alternative method to [migrate an existing repository to Git LFS](https://github.com/git-lfs/git-lfs/wiki/Tutorial#migrating-existing-repository-data-to-lfs)
|
||||
|
|
|
@ -27,8 +27,6 @@ of top-performing instances based on [usage ping data](../settings/usage_statist
|
|||
collected. Your score is compared to the lead score of each feature and then expressed as a percentage at the bottom of said feature.
|
||||
Your overall **DevOps Score** is an average of your feature scores. You can use this score to compare your DevOps status to other organizations.
|
||||
|
||||
![DevOps Report](img/dev_ops_report_v13_4.png)
|
||||
|
||||
The page also provides helpful links to articles and GitLab docs, to help you
|
||||
improve your scores.
|
||||
|
||||
|
@ -58,8 +56,6 @@ DevOps Adoption allows you to:
|
|||
- Identify specific groups that are lagging in their adoption of GitLab so you can help them along in their DevOps journey.
|
||||
- Find the groups that have adopted certain features and can provide guidance to other groups on how to use those features.
|
||||
|
||||
![DevOps Report](img/dev_ops_adoption_v13_9.png)
|
||||
|
||||
### Disable or enable DevOps Adoption
|
||||
|
||||
DevOps Adoption is deployed behind a feature flag that is **disabled by default**.
|
||||
|
|
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 50 KiB |
|
@ -16,9 +16,7 @@ section.
|
|||
|
||||
By default, the navigation bar has the GitLab logo, but this can be customized with
|
||||
any image desired. It is optimized for images 28px high (any width), but any image can be
|
||||
used (less than 1MB) and it is automatically resized.
|
||||
|
||||
![Navigation bar header logo screenshot](img/appearance_header_logo_v12_3.png)
|
||||
used (less than 1 MB) and it is automatically resized.
|
||||
|
||||
After you select and upload an image, click **Update appearance settings** at the bottom
|
||||
of the page to activate it in the GitLab instance.
|
||||
|
@ -34,8 +32,6 @@ By default, the favicon (used by the browser as the tab icon, as well as the CI
|
|||
uses the GitLab logo, but this can be customized with any icon desired. It must be a
|
||||
32x32 `.png` or `.ico` image.
|
||||
|
||||
![favicon screenshot](img/appearance_favicon_v12_3.png)
|
||||
|
||||
After you select and upload an icon, click **Update appearance settings** at the bottom
|
||||
of the page to activate it in the GitLab instance.
|
||||
|
||||
|
@ -52,8 +48,6 @@ Limited [Markdown](../markdown.md) is supported, such as bold, italics, and link
|
|||
example. Other Markdown features, including lists, images, and quotes are not supported
|
||||
as the header and footer messages can only be a single line.
|
||||
|
||||
![header and footer screenshot](img/appearance_header_footer_v12_3.png)
|
||||
|
||||
If desired, you can select **Enable header and footer in emails** to have the text of
|
||||
the header and footer added to all emails sent by the GitLab instance.
|
||||
|
||||
|
@ -63,16 +57,12 @@ to activate it in the GitLab instance.
|
|||
## Sign in / Sign up pages
|
||||
|
||||
You can replace the default message on the sign in / sign up page with your own message
|
||||
and logo. You can make full use of [Markdown](../markdown.md) in the description:
|
||||
|
||||
![sign in message screenshot](img/appearance_sign_in_v12_3.png)
|
||||
and logo. You can make full use of [Markdown](../markdown.md) in the description.
|
||||
|
||||
The optimal size for the logo is 640x360px, but any image can be used (below 1MB)
|
||||
and it is resized automatically. The logo image appears between the title and
|
||||
the description, on the left of the sign-up page.
|
||||
|
||||
![sign in message preview screenshot](img/appearance_sign_in_preview_v12_3.png)
|
||||
|
||||
After you add a message, click **Update appearance settings** at the bottom of the page
|
||||
to activate it in the GitLab instance. You can also click on the **Sign-in page** button,
|
||||
to review the saved appearance settings:
|
||||
|
@ -85,8 +75,6 @@ You can add also add a [customized help message](settings/help_page.md) below th
|
|||
You can add a new project guidelines message to the **New project page** within GitLab.
|
||||
You can make full use of [Markdown](../markdown.md) in the description:
|
||||
|
||||
![new project message screenshot](img/appearance_new_project_v12_3.png)
|
||||
|
||||
The message is displayed below the **New Project** message, on the left side
|
||||
of the **New project page**.
|
||||
|
||||
|
@ -94,8 +82,6 @@ After you add a message, click **Update appearance settings** at the bottom of t
|
|||
to activate it in the GitLab instance. You can also click on the **New project page**
|
||||
button, which brings you to the new project page so you can review the change.
|
||||
|
||||
![new project message preview screenshot](img/appearance_new_project_preview_v12_3.png)
|
||||
|
||||
## Libravatar
|
||||
|
||||
[Libravatar](https://www.libravatar.org) is supported by GitLab for avatar images, but you must
|
||||
|
|
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 119 KiB |
|
@ -18,13 +18,8 @@ You can add a help message, which is shown on the GitLab `/help` page (e.g.,
|
|||
|
||||
1. Navigate to **Admin Area > Settings > Preferences**, then expand **Help page**.
|
||||
1. Under **Help page text**, fill in the information you wish to display on `/help`.
|
||||
|
||||
![help page help message](img/help_page_help_page_text_v12_3.png)
|
||||
|
||||
1. Save your changes. You can now see the message on `/help`.
|
||||
|
||||
![help message on help page example](img/help_page_help_page_text_ex_v12_3.png)
|
||||
|
||||
## Adding a help message to the login page **(STARTER)**
|
||||
|
||||
You can add a help message, which is shown on the GitLab login page in a new section
|
||||
|
|
Before Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 23 KiB |
|
@ -15,7 +15,7 @@ To see user cohorts, go to **Admin Area > Overview > Users**.
|
|||
How do you interpret the user cohorts table? Let's review an example with the
|
||||
following user cohorts:
|
||||
|
||||
![User cohort example](img/cohorts_v13_9.png)
|
||||
![User cohort example](img/cohorts_v13_9_a.png)
|
||||
|
||||
For the cohort of March 2020, three users were added to this server and have
|
||||
been active since this month. One month later (April 2020), two users are still
|
||||
|
|
|
@ -6,14 +6,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Feature highlight
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/16379) in GitLab 10.5
|
||||
|
||||
Feature highlights are represented by a pulsing blue dot. Hovering over the dot
|
||||
displays more information.
|
||||
They are used to emphasize a certain feature and make something more visible to the user.
|
||||
displays more information. They're used to emphasize certain features and
|
||||
highlight helpful information to the user.
|
||||
|
||||
You can dismiss any feature highlight permanently by clicking the "Got it" link
|
||||
at the bottom of the modal window. There isn't a way to restore the feature highlight
|
||||
after it has been dismissed.
|
||||
|
||||
![Clusters feature highlight](img/feature_highlight_example.png)
|
||||
You can dismiss any feature highlight permanently by clicking the **Got it** link
|
||||
at the bottom of the information window. You cannot restore a feature highlight
|
||||
after you dismiss it.
|
||||
|
|
Before Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 27 KiB |
|
@ -86,10 +86,11 @@ There are several types of users in GitLab:
|
|||
## User activity
|
||||
|
||||
You can follow or unfollow other users from their [user profiles](profile/index.md#access-your-user-profile).
|
||||
To see their activity in the top-level Activity view, select Follow or Unfollow, and select
|
||||
the Followed Users tab:
|
||||
To view a user's activity in a top-level Activity view:
|
||||
|
||||
![Follow users](img/activity_followed_users_v13_9.png)
|
||||
1. From a user's profile, select **Follow**.
|
||||
1. In the GitLab menu, select **Activity**.
|
||||
1. Select the **Followed users** tab.
|
||||
|
||||
## Projects
|
||||
|
||||
|
|
|
@ -143,6 +143,10 @@ But you have the option to [invite](members/share_project_with_groups.md)
|
|||
the Subgroup Y to the Project A so that their members also become eligible
|
||||
Code Owners:
|
||||
|
||||
NOTE:
|
||||
If you do not invite Subgroup Y to Project A, but make them Code Owners, their approval
|
||||
of the merge request becomes optional.
|
||||
|
||||
![Invite subgroup members to become eligible Code Owners](img/code_owners_invite_members_v13_4.png)
|
||||
|
||||
After being invited, any member (`@user`) of the group or subgroup can be set
|
||||
|
|
|
@ -62,9 +62,16 @@ For this association to succeed, each GitHub author and assignee in the reposito
|
|||
must meet one of the following conditions prior to the import:
|
||||
|
||||
- Have previously logged in to a GitLab account using the GitHub icon.
|
||||
- Have a GitHub account with a publicly visible
|
||||
[primary email address](https://docs.github.com/en/rest/reference/users#get-a-user)
|
||||
on their profile that matches their GitLab account's primary or secondary email address.
|
||||
- Have a GitHub account with a [public-facing email address](https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/setting-your-commit-email-address)
|
||||
that matches their GitLab account's email address.
|
||||
|
||||
NOTE:
|
||||
GitLab content imports that use GitHub accounts require that the GitHub public-facing
|
||||
email address is populated so that all comments and contributions are properly mapped
|
||||
to the same user in GitLab. GitHub Enterprise (on premise) does not require this field
|
||||
to be populated to use the product, so you may need to add it on existing GitHub Enterprise
|
||||
accounts for imported content to be properly mapped to the user in the new system.
|
||||
Refer to GitHub documentation for instructions on how to add that address.
|
||||
|
||||
If a user referenced in the project is not found in the GitLab database, the project creator (typically the user
|
||||
that initiated the import process) is set as the author/assignee, but a note on the issue mentioning the original
|
||||
|
|
Before Width: | Height: | Size: 11 KiB |
|
@ -20,9 +20,7 @@ This feature is [also available at the group level](../../group/insights/index.m
|
|||
## View your project's Insights
|
||||
|
||||
You can access your project's Insights by clicking the **Analytics > Insights**
|
||||
link in the left sidebar:
|
||||
|
||||
![Insights sidebar link](img/insights_sidebar_link_v12_8.png)
|
||||
link in the left sidebar.
|
||||
|
||||
## Configure your Insights
|
||||
|
||||
|
|
|
@ -4,32 +4,50 @@ group: Ecosystem
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Hangouts Chat service **(FREE)**
|
||||
# Google Chat integration **(FREE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/43756) in GitLab 11.2.
|
||||
|
||||
The Hangouts Chat service sends notifications from GitLab to the room for which the webhook was created.
|
||||
Integrate your project to send notifications from GitLab to a
|
||||
room of your choice in [Google Chat](https://chat.google.com/) (former Google
|
||||
Hangouts).
|
||||
|
||||
## On Hangouts Chat
|
||||
## How it works
|
||||
|
||||
1. Open the chat room in which you want to see the notifications.
|
||||
1. From the chat room menu, select **Configure Webhooks**.
|
||||
1. Click on **ADD WEBHOOK** and fill in the name of the bot to post the messages. Optionally define an avatar.
|
||||
1. Click **SAVE** and copy the **Webhook URL** of your webhook.
|
||||
To enable this integration, first you need to create a webhook for the room in
|
||||
Google Chat where you want to receive the nofications from your project.
|
||||
|
||||
See also [the Hangouts Chat documentation for configuring incoming webhooks](https://developers.google.com/hangouts/chat/how-tos/webhooks)
|
||||
After that, enable the integration in GitLab and choose the events you want to
|
||||
be notified about in your Google Chat room.
|
||||
|
||||
## On GitLab
|
||||
For every selected event in your project, GitLab acts like a bot sending
|
||||
notifications to Google Chat:
|
||||
|
||||
When you have the **Webhook URL** for your Hangouts Chat room webhook, you can set up the GitLab service.
|
||||
![Google Chat integration illustration](img/google_chat_integration_v13_11.png)
|
||||
|
||||
1. Navigate to the [Integrations page](overview.md#accessing-integrations) in your project's settings, i.e. **Project > Settings > Integrations**.
|
||||
1. Select the **Hangouts Chat** integration to configure it.
|
||||
1. Ensure that the **Active** toggle is enabled.
|
||||
1. Check the checkboxes corresponding to the GitLab events you want to receive.
|
||||
1. Paste the **Webhook URL** that you copied from the Hangouts Chat configuration step.
|
||||
1. Configure the remaining options and click `Save changes`.
|
||||
## In Google Chat
|
||||
|
||||
Your Hangouts Chat room now starts receiving GitLab event notifications as configured.
|
||||
Select a room and create a webhook:
|
||||
|
||||
![Hangouts Chat configuration](img/hangouts_chat_configuration.png)
|
||||
1. Enter the room where you want to receive notifications from GitLab.
|
||||
1. Open the room dropdown menu on the top-left and select **Manage webhooks**.
|
||||
1. Enter the name for your webhook, for example "GitLab integration".
|
||||
1. (Optional) Add an avatar for your bot.
|
||||
1. Select **Save**.
|
||||
1. Copy the webhook URL.
|
||||
|
||||
For further details, see [the Google Chat documentation for configuring webhooks](https://developers.google.com/hangouts/chat/how-tos/webhooks).
|
||||
|
||||
## In GitLab
|
||||
|
||||
Enable the Google Chat integration in GitLab:
|
||||
|
||||
1. In your project, go to **Settings > Integrations** and select **Google Chat**.
|
||||
1. Scroll down to the end of the page where you find a **Webhook** field.
|
||||
1. Enter the webhook URL you copied from Google Chat.
|
||||
1. Select the events you want to be notified about in your Google Chat room.
|
||||
1. (Optional) Select **Test settings** to verify the connection.
|
||||
1. Select **Save changes**.
|
||||
|
||||
To test the integration, make a change based on the events you selected and
|
||||
see the notification in your Google Chat room.
|
||||
|
|
After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 29 KiB |
|
@ -39,9 +39,9 @@ Click on the service links to see further configuration instructions and details
|
|||
| [Emails on push](emails_on_push.md) | Send commits and diff of each push by email. | **{dotted-circle}** No |
|
||||
| [EWM](ewm.md) | Use IBM Engineering Workflow Management as the issue tracker. | **{dotted-circle}** No |
|
||||
| [External wiki](../wiki/index.md#link-an-external-wiki) | Link an external wiki. | **{dotted-circle}** No |
|
||||
| Flowdock | Use Flowdock with GitLab. | **{dotted-circle}** No |
|
||||
| [Flowdock](../../../api/services.md#flowdock) | Send notifications from GitLab to Flowdock flows. | **{dotted-circle}** No |
|
||||
| [GitHub](github.md) | Obtain statuses for commits and pull requests. | **{dotted-circle}** No |
|
||||
| [Hangouts Chat](hangouts_chat.md) | Receive events notifications. | **{dotted-circle}** No |
|
||||
| [Google Chat](hangouts_chat.md) | Send notifications from your GitLab project to a room in Google Chat.| **{dotted-circle}** No |
|
||||
| [Irker (IRC gateway)](irker.md) | Send IRC messages. | **{dotted-circle}** No |
|
||||
| [Jenkins](../../../integration/jenkins.md) | Run CI/CD pipelines with Jenkins. | **{check-circle}** Yes |
|
||||
| JetBrains TeamCity CI | Run CI/CD pipelines with TeamCity. | **{check-circle}** Yes |
|
||||
|
|
Before Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 64 KiB |
|
@ -28,22 +28,14 @@ This is where the group sharing feature can be of use.
|
|||
To share 'Project Acme' with the 'Engineering' group:
|
||||
|
||||
1. For 'Project Acme' use the left navigation menu to go to **Members**.
|
||||
|
||||
![share project with groups](img/share_project_with_groups_tab_v13_9.png)
|
||||
|
||||
1. Select the **Invite group** tab.
|
||||
1. Add the 'Engineering' group with the maximum access level of your choice.
|
||||
1. Optionally, select an expiring date.
|
||||
1. Click **Invite**.
|
||||
1. After sharing 'Project Acme' with 'Engineering':
|
||||
- The group is listed in the **Groups** tab.
|
||||
|
||||
!['Engineering' group is listed in Groups tab](img/project_groups_tab_v13_9.png)
|
||||
|
||||
- The project is listed on the group dashboard.
|
||||
|
||||
!['Project Acme' is listed as a shared project for 'Engineering'](img/other_group_sees_shared_project_v13_8.png)
|
||||
|
||||
Note that you can only share a project with:
|
||||
|
||||
- groups for which you have an explicitly defined membership
|
||||
|
|
|
@ -13,7 +13,5 @@ time_frame: <%= time_frame %>
|
|||
data_source:
|
||||
distribution:
|
||||
<%= distribution %>
|
||||
# tier:
|
||||
# - free
|
||||
# - premium
|
||||
# - ultimate
|
||||
tier:
|
||||
<%= tier %>
|
||||
|
|
|
@ -88,11 +88,8 @@ module API
|
|||
end
|
||||
|
||||
def fetch_package(file_name:, project: nil, group: nil)
|
||||
order_by_package_file = false
|
||||
if Feature.enabled?(:maven_packages_group_level_improvements, default_enabled: :yaml)
|
||||
order_by_package_file = file_name.include?(::Packages::Maven::Metadata.filename) &&
|
||||
!params[:path].include?(::Packages::Maven::FindOrCreatePackageService::SNAPSHOT_TERM)
|
||||
end
|
||||
order_by_package_file = file_name.include?(::Packages::Maven::Metadata.filename) &&
|
||||
!params[:path].include?(::Packages::Maven::FindOrCreatePackageService::SNAPSHOT_TERM)
|
||||
|
||||
::Packages::Maven::PackageFinder.new(
|
||||
params[:path],
|
||||
|
|
|
@ -53,9 +53,11 @@ module Gitlab
|
|||
end
|
||||
|
||||
def distribution
|
||||
value = ['- ce']
|
||||
value << '- ee' if ee?
|
||||
value.join("\n")
|
||||
(ee? ? ['- ee'] : ['- ce', '- ee']).join("\n")
|
||||
end
|
||||
|
||||
def tier
|
||||
(ee? ? ['#- premium', '- ultimate'] : ['- free', '- premium', '- ultimate']).join("\n")
|
||||
end
|
||||
|
||||
def milestone
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Database
|
||||
module MigrationHelpers
|
||||
module CascadingNamespaceSettings
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
# Creates the four required columns that constitutes a single cascading
|
||||
# namespace settings attribute. This helper is only appropriate if the
|
||||
# setting is not already present as a non-cascading attribute.
|
||||
#
|
||||
# Creates the `setting_name` column along with the `lock_setting_name`
|
||||
# column in both `namespace_settings` and `application_settings`.
|
||||
#
|
||||
# This helper is not reversible and must be defined in conjunction with
|
||||
# `remove_cascading_namespace_setting` in separate up and down directions.
|
||||
#
|
||||
# setting_name - The name of the cascading attribute - same as defined
|
||||
# in `NamespaceSetting` with the `cascading_attr` method.
|
||||
# type - The column type for the setting itself (:boolean, :integer, etc.)
|
||||
# options - Standard Rails column options hash. Accepts keys such as
|
||||
# `null` and `default`.
|
||||
#
|
||||
# `null` and `default` options will only be applied to the `application_settings`
|
||||
# column. In most cases, a non-null default value should be specified.
|
||||
def add_cascading_namespace_setting(setting_name, type, **options)
|
||||
lock_column_name = "lock_#{setting_name}".to_sym
|
||||
|
||||
check_cascading_namespace_setting_consistency(setting_name, lock_column_name)
|
||||
|
||||
namespace_options = options.merge(null: true, default: nil)
|
||||
|
||||
with_lock_retries do
|
||||
add_column(:namespace_settings, setting_name, type, namespace_options)
|
||||
add_column(:namespace_settings, lock_column_name, :boolean, default: false, null: false)
|
||||
end
|
||||
|
||||
add_column(:application_settings, setting_name, type, options)
|
||||
add_column(:application_settings, lock_column_name, :boolean, default: false, null: false)
|
||||
end
|
||||
|
||||
def remove_cascading_namespace_setting(setting_name)
|
||||
lock_column_name = "lock_#{setting_name}".to_sym
|
||||
|
||||
with_lock_retries do
|
||||
remove_column(:namespace_settings, setting_name) if column_exists?(:namespace_settings, setting_name)
|
||||
remove_column(:namespace_settings, lock_column_name) if column_exists?(:namespace_settings, lock_column_name)
|
||||
end
|
||||
|
||||
remove_column(:application_settings, setting_name) if column_exists?(:application_settings, setting_name)
|
||||
remove_column(:application_settings, lock_column_name) if column_exists?(:application_settings, lock_column_name)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_cascading_namespace_setting_consistency(setting_name, lock_name)
|
||||
existing_columns = []
|
||||
|
||||
%w(namespace_settings application_settings).each do |table|
|
||||
existing_columns << "#{table}.#{setting_name}" if column_exists?(table.to_sym, setting_name)
|
||||
existing_columns << "#{table}.#{lock_name}" if column_exists?(table.to_sym, lock_name)
|
||||
end
|
||||
|
||||
return if existing_columns.empty?
|
||||
|
||||
raise <<~ERROR
|
||||
One or more cascading namespace columns already exist. `add_cascading_namespace_setting` helper
|
||||
can only be used for new settings, when none of the required columns already exist.
|
||||
Existing columns: #{existing_columns.join(', ')}
|
||||
ERROR
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1937,6 +1937,9 @@ msgstr ""
|
|||
msgid "Add bold text"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add broadcast message"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add child epic to an epic"
|
||||
msgstr ""
|
||||
|
||||
|
@ -4935,6 +4938,9 @@ msgstr ""
|
|||
msgid "Be careful. Renaming a project's repository can have unintended side effects."
|
||||
msgstr ""
|
||||
|
||||
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Before inserting code, be sure to read the comment that separated each code group."
|
||||
msgstr ""
|
||||
|
||||
|
@ -13930,10 +13936,13 @@ msgstr ""
|
|||
msgid "Flags"
|
||||
msgstr ""
|
||||
|
||||
msgid "FlowdockService|Flowdock Git source token"
|
||||
msgid "FlowdockService|1b609b52537..."
|
||||
msgstr ""
|
||||
|
||||
msgid "FlowdockService|Flowdock is a collaboration web app for technical teams."
|
||||
msgid "FlowdockService|Send event notifications from GitLab to Flowdock flows."
|
||||
msgstr ""
|
||||
|
||||
msgid "FlowdockService|Send event notifications from GitLab to Flowdock flows. %{docs_link}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Focus filter bar"
|
||||
|
@ -16082,6 +16091,9 @@ msgstr ""
|
|||
msgid "How do I mirror repositories?"
|
||||
msgstr ""
|
||||
|
||||
msgid "How do I set up a Google Chat webhook?"
|
||||
msgstr ""
|
||||
|
||||
msgid "How do I set up this service?"
|
||||
msgstr ""
|
||||
|
||||
|
@ -31166,16 +31178,28 @@ msgstr ""
|
|||
msgid "TestReports|Jobs"
|
||||
msgstr ""
|
||||
|
||||
msgid "TestReports|Learn how to upload pipeline test reports"
|
||||
msgstr ""
|
||||
|
||||
msgid "TestReports|Learn more about pipeline test reports"
|
||||
msgstr ""
|
||||
|
||||
msgid "TestReports|No test cases were found in the test report."
|
||||
msgstr ""
|
||||
|
||||
msgid "TestReports|Tests"
|
||||
msgstr ""
|
||||
|
||||
msgid "TestReports|There are no test cases to display."
|
||||
msgstr ""
|
||||
|
||||
msgid "TestReports|There are no test reports for this pipeline"
|
||||
msgstr ""
|
||||
|
||||
msgid "TestReports|There are no test suites to show."
|
||||
msgstr ""
|
||||
|
||||
msgid "TestReports|There are no tests to show."
|
||||
msgid "TestReports|There are no tests to display"
|
||||
msgstr ""
|
||||
|
||||
msgid "TestReports|There was an error fetching the summary."
|
||||
|
@ -31184,6 +31208,9 @@ msgstr ""
|
|||
msgid "TestReports|There was an error fetching the test suite."
|
||||
msgstr ""
|
||||
|
||||
msgid "TestReports|You can configure your job to use unit test reports, and GitLab displays a report here and in the related merge request."
|
||||
msgstr ""
|
||||
|
||||
msgid "Tests"
|
||||
msgstr ""
|
||||
|
||||
|
@ -33888,6 +33915,9 @@ msgstr ""
|
|||
msgid "Update approvers"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update broadcast message"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update failed"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -109,6 +109,20 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
trait :cilium do
|
||||
monitoring_tool { Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:cilium] }
|
||||
payload do
|
||||
{
|
||||
annotations: {
|
||||
title: 'This is a cilium alert',
|
||||
summary: 'Summary of the alert',
|
||||
description: 'Description of the alert'
|
||||
},
|
||||
startsAt: started_at
|
||||
}.with_indifferent_access
|
||||
end
|
||||
end
|
||||
|
||||
trait :all_fields do
|
||||
with_issue
|
||||
with_assignee
|
||||
|
|
|
@ -47,23 +47,7 @@ RSpec.describe ::Packages::Maven::PackageFinder do
|
|||
context 'within a group' do
|
||||
let(:param_group) { group }
|
||||
|
||||
context 'with maven_packages_group_level_improvements enabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: true)
|
||||
expect(finder).to receive(:packages_visible_to_user).with(user, within_group: group).and_call_original
|
||||
end
|
||||
|
||||
it_behaves_like 'handling valid and invalid paths'
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements disabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: false)
|
||||
expect(finder).not_to receive(:packages_visible_to_user)
|
||||
end
|
||||
|
||||
it_behaves_like 'handling valid and invalid paths'
|
||||
end
|
||||
it_behaves_like 'handling valid and invalid paths'
|
||||
end
|
||||
|
||||
context 'across all projects' do
|
||||
|
@ -93,38 +77,14 @@ RSpec.describe ::Packages::Maven::PackageFinder do
|
|||
create(:package_file, :xml, package: package2)
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements enabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: true)
|
||||
expect(finder).not_to receive(:versionless_package?)
|
||||
end
|
||||
|
||||
context 'without order by package file' do
|
||||
it { is_expected.to eq(package3) }
|
||||
end
|
||||
|
||||
context 'with order by package file' do
|
||||
let(:param_order_by_package_file) { true }
|
||||
|
||||
it { is_expected.to eq(package2) }
|
||||
end
|
||||
context 'without order by package file' do
|
||||
it { is_expected.to eq(package3) }
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements disabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: false)
|
||||
expect(finder).to receive(:versionless_package?).and_call_original
|
||||
end
|
||||
context 'with order by package file' do
|
||||
let(:param_order_by_package_file) { true }
|
||||
|
||||
context 'without order by package file' do
|
||||
it { is_expected.to eq(package2) }
|
||||
end
|
||||
|
||||
context 'with order by package file' do
|
||||
let(:param_order_by_package_file) { true }
|
||||
|
||||
it { is_expected.to eq(package2) }
|
||||
end
|
||||
it { is_expected.to eq(package2) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
19
spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
key_path: counts_weekly.test_metric
|
||||
name: test metric name
|
||||
description:
|
||||
product_section:
|
||||
product_stage:
|
||||
product_group:
|
||||
product_category:
|
||||
value_type: number
|
||||
status: implemented
|
||||
milestone: "13.9"
|
||||
introduced_by_url:
|
||||
time_frame: 7d
|
||||
data_source:
|
||||
distribution:
|
||||
- ee
|
||||
tier:
|
||||
#- premium
|
||||
- ultimate
|
|
@ -15,8 +15,8 @@ time_frame: 7d
|
|||
data_source:
|
||||
distribution:
|
||||
- ce
|
||||
# Add here corresponding tiers
|
||||
# tier:
|
||||
# - free
|
||||
# - premium
|
||||
# - ultimate
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import { GlEmptyState } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import EmptyState, { i18n } from '~/pipelines/components/test_reports/empty_state.vue';
|
||||
|
||||
describe('Test report empty state', () => {
|
||||
let wrapper;
|
||||
|
||||
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
|
||||
|
||||
const createComponent = ({ hasTestReport = true } = {}) => {
|
||||
wrapper = shallowMount(EmptyState, {
|
||||
provide: {
|
||||
emptyStateImagePath: '/image/path',
|
||||
hasTestReport,
|
||||
},
|
||||
stubs: {
|
||||
GlEmptyState,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
describe('when pipeline has a test report', () => {
|
||||
it('should render empty test report message', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findEmptyState().props()).toMatchObject({
|
||||
primaryButtonText: i18n.noTestsButton,
|
||||
description: i18n.noTestsDescription,
|
||||
title: i18n.noTestsTitle,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when pipeline does not have a test report', () => {
|
||||
it('should render no test report message', () => {
|
||||
createComponent({ hasTestReport: false });
|
||||
|
||||
expect(findEmptyState().props()).toMatchObject({
|
||||
primaryButtonText: i18n.noReportsButton,
|
||||
description: i18n.noReportsDescription,
|
||||
title: i18n.noReportsTitle,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -2,6 +2,8 @@ import { GlLoadingIcon } from '@gitlab/ui';
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import { getJSONFixture } from 'helpers/fixtures';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import EmptyState from '~/pipelines/components/test_reports/empty_state.vue';
|
||||
import TestReports from '~/pipelines/components/test_reports/test_reports.vue';
|
||||
import TestSummary from '~/pipelines/components/test_reports/test_summary.vue';
|
||||
import TestSummaryTable from '~/pipelines/components/test_reports/test_summary_table.vue';
|
||||
|
@ -16,11 +18,11 @@ describe('Test reports app', () => {
|
|||
|
||||
const testReports = getJSONFixture('pipelines/test_report.json');
|
||||
|
||||
const loadingSpinner = () => wrapper.find(GlLoadingIcon);
|
||||
const testsDetail = () => wrapper.find('[data-testid="tests-detail"]');
|
||||
const noTestsToShow = () => wrapper.find('[data-testid="no-tests-to-show"]');
|
||||
const testSummary = () => wrapper.find(TestSummary);
|
||||
const testSummaryTable = () => wrapper.find(TestSummaryTable);
|
||||
const loadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const testsDetail = () => wrapper.findByTestId('tests-detail');
|
||||
const emptyState = () => wrapper.findComponent(EmptyState);
|
||||
const testSummary = () => wrapper.findComponent(TestSummary);
|
||||
const testSummaryTable = () => wrapper.findComponent(TestSummaryTable);
|
||||
|
||||
const actionSpies = {
|
||||
fetchTestSuite: jest.fn(),
|
||||
|
@ -29,7 +31,7 @@ describe('Test reports app', () => {
|
|||
removeSelectedSuiteIndex: jest.fn(),
|
||||
};
|
||||
|
||||
const createComponent = (state = {}) => {
|
||||
const createComponent = ({ state = {}, hasTestReport = true } = {}) => {
|
||||
store = new Vuex.Store({
|
||||
state: {
|
||||
isLoading: false,
|
||||
|
@ -41,10 +43,15 @@ describe('Test reports app', () => {
|
|||
getters,
|
||||
});
|
||||
|
||||
wrapper = shallowMount(TestReports, {
|
||||
store,
|
||||
localVue,
|
||||
});
|
||||
wrapper = extendedWrapper(
|
||||
shallowMount(TestReports, {
|
||||
store,
|
||||
localVue,
|
||||
provide: {
|
||||
hasTestReport,
|
||||
},
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -52,33 +59,34 @@ describe('Test reports app', () => {
|
|||
});
|
||||
|
||||
describe('when component is created', () => {
|
||||
beforeEach(() => {
|
||||
it('should call fetchSummary when pipeline has test report', () => {
|
||||
createComponent();
|
||||
|
||||
expect(actionSpies.fetchSummary).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call fetchSummary', () => {
|
||||
expect(actionSpies.fetchSummary).toHaveBeenCalled();
|
||||
it('should not call fetchSummary when pipeline does not have test report', () => {
|
||||
createComponent({ state: {}, hasTestReport: false });
|
||||
|
||||
expect(actionSpies.fetchSummary).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when loading', () => {
|
||||
beforeEach(() => createComponent({ isLoading: true }));
|
||||
beforeEach(() => createComponent({ state: { isLoading: true } }));
|
||||
|
||||
it('shows the loading spinner', () => {
|
||||
expect(noTestsToShow().exists()).toBe(false);
|
||||
expect(emptyState().exists()).toBe(false);
|
||||
expect(testsDetail().exists()).toBe(false);
|
||||
expect(loadingSpinner().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the api returns no data', () => {
|
||||
beforeEach(() => createComponent({ testReports: {} }));
|
||||
it('displays empty state component', () => {
|
||||
createComponent({ state: { testReports: {} } });
|
||||
|
||||
it('displays that there are no tests to show', () => {
|
||||
const noTests = noTestsToShow();
|
||||
|
||||
expect(noTests.exists()).toBe(true);
|
||||
expect(noTests.text()).toBe('There are no tests to show.');
|
||||
expect(emptyState().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -97,7 +105,7 @@ describe('Test reports app', () => {
|
|||
|
||||
describe('when a suite is clicked', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ hasFullReport: true });
|
||||
createComponent({ state: { hasFullReport: true } });
|
||||
testSummaryTable().vm.$emit('row-click', 0);
|
||||
});
|
||||
|
||||
|
@ -109,7 +117,7 @@ describe('Test reports app', () => {
|
|||
|
||||
describe('when clicking back to summary', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ selectedSuiteIndex: 0 });
|
||||
createComponent({ state: { selectedSuiteIndex: 0 } });
|
||||
testSummary().vm.$emit('on-back-click');
|
||||
});
|
||||
|
||||
|
|
|
@ -33,19 +33,6 @@ describe('~/whats_new/utils/notification', () => {
|
|||
expect(notificationEl.classList).toContain('with-notifications');
|
||||
});
|
||||
|
||||
it('removes class and count element when legacy storage key is false', () => {
|
||||
const notificationEl = findNotificationEl();
|
||||
notificationEl.classList.add('with-notifications');
|
||||
localStorage.setItem('display-whats-new-notification-13.10', 'false');
|
||||
|
||||
expect(findNotificationCountEl()).toExist();
|
||||
|
||||
subject();
|
||||
|
||||
expect(findNotificationCountEl()).not.toExist();
|
||||
expect(notificationEl.classList).not.toContain('with-notifications');
|
||||
});
|
||||
|
||||
it('removes class and count element when storage key has current digest', () => {
|
||||
const notificationEl = findNotificationEl();
|
||||
notificationEl.classList.add('with-notifications');
|
||||
|
|
|
@ -20,20 +20,37 @@ RSpec.describe Gitlab::UsageMetricDefinitionGenerator do
|
|||
end
|
||||
|
||||
describe 'Creating metric definition file' do
|
||||
let(:sample_metric) { load_sample_metric_definition(filename: sample_filename) }
|
||||
|
||||
# Stub version so that `milestone` key remains constant between releases to prevent flakiness.
|
||||
before do
|
||||
stub_const('Gitlab::VERSION', '13.9.0')
|
||||
allow(::Gitlab::Usage::Metrics::NamesSuggestions::Generator).to receive(:generate).and_return('test metric name')
|
||||
end
|
||||
|
||||
let(:sample_metric) { load_sample_metric_definition(filename: 'sample_metric_with_name_suggestions.yml') }
|
||||
context 'without ee option' do
|
||||
let(:sample_filename) { 'sample_metric_with_name_suggestions.yml' }
|
||||
let(:metric_definition_path) { Dir.glob(File.join(temp_dir, 'metrics/counts_7d/*_test_metric.yml')).first }
|
||||
|
||||
it 'creates a metric definition file using the template' do
|
||||
described_class.new([key_path], { 'dir' => dir }).invoke_all
|
||||
it 'creates a metric definition file using the template' do
|
||||
described_class.new([key_path], { 'dir' => dir }).invoke_all
|
||||
expect(YAML.safe_load(File.read(metric_definition_path))).to eq(sample_metric)
|
||||
end
|
||||
end
|
||||
|
||||
metric_definition_path = Dir.glob(File.join(temp_dir, 'metrics/counts_7d/*_test_metric.yml')).first
|
||||
context 'with ee option' do
|
||||
let(:sample_filename) { 'sample_metric_with_ee.yml' }
|
||||
let(:metric_definition_path) { Dir.glob(File.join(temp_dir, 'ee/config/metrics/counts_7d/*_test_metric.yml')).first }
|
||||
|
||||
expect(YAML.safe_load(File.read(metric_definition_path))).to eq(sample_metric)
|
||||
before do
|
||||
stub_const("#{described_class}::TOP_LEVEL_DIR", 'config')
|
||||
stub_const("#{described_class}::TOP_LEVEL_DIR_EE", File.join(temp_dir, 'ee'))
|
||||
end
|
||||
|
||||
it 'creates a metric definition file using the template' do
|
||||
described_class.new([key_path], { 'dir' => dir, 'ee': true }).invoke_all
|
||||
expect(YAML.safe_load(File.read(metric_definition_path))).to eq(sample_metric)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings do
|
||||
let(:migration) do
|
||||
ActiveRecord::Migration.new.extend(described_class)
|
||||
end
|
||||
|
||||
describe '#add_cascading_namespace_setting' do
|
||||
it 'creates the required columns', :aggregate_failures do
|
||||
expect(migration).to receive(:add_column).with(:namespace_settings, :some_setting, :integer, null: true, default: nil)
|
||||
expect(migration).to receive(:add_column).with(:namespace_settings, :lock_some_setting, :boolean, null: false, default: false)
|
||||
|
||||
expect(migration).to receive(:add_column).with(:application_settings, :some_setting, :integer, null: false, default: 5)
|
||||
expect(migration).to receive(:add_column).with(:application_settings, :lock_some_setting, :boolean, null: false, default: false)
|
||||
|
||||
migration.add_cascading_namespace_setting(:some_setting, :integer, null: false, default: 5)
|
||||
end
|
||||
|
||||
context 'when columns already exist' do
|
||||
before do
|
||||
migration.add_column(:namespace_settings, :cascading_setting, :integer)
|
||||
migration.add_column(:application_settings, :lock_cascading_setting, :boolean)
|
||||
end
|
||||
|
||||
it 'raises an error when some columns already exist' do
|
||||
expect do
|
||||
migration.add_cascading_namespace_setting(:cascading_setting, :integer)
|
||||
end.to raise_error %r/Existing columns: namespace_settings.cascading_setting, application_settings.lock_cascading_setting/
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#remove_cascading_namespace_setting' do
|
||||
before do
|
||||
allow(migration).to receive(:column_exists?).and_return(true)
|
||||
end
|
||||
|
||||
it 'removes the columns', :aggregate_failures do
|
||||
expect(migration).to receive(:remove_column).with(:namespace_settings, :some_setting)
|
||||
expect(migration).to receive(:remove_column).with(:namespace_settings, :lock_some_setting)
|
||||
|
||||
expect(migration).to receive(:remove_column).with(:application_settings, :some_setting)
|
||||
expect(migration).to receive(:remove_column).with(:application_settings, :lock_some_setting)
|
||||
|
||||
migration.remove_cascading_namespace_setting(:some_setting)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -63,7 +63,7 @@ RSpec.describe Gitlab::UsageDataQueries do
|
|||
it 'returns the histogram sql' do
|
||||
expect(described_class.histogram(AlertManagement::HttpIntegration.active,
|
||||
:project_id, buckets: 1..2, bucket_size: 101))
|
||||
.to eq('WITH "count_cte" AS (SELECT COUNT(*) AS count_grouped FROM "alert_management_http_integrations" WHERE "alert_management_http_integrations"."active" = TRUE GROUP BY "alert_management_http_integrations"."project_id") SELECT WIDTH_BUCKET("count_cte"."count_grouped", 1, 2, 100) AS buckets, "count_cte"."count" FROM "count_cte" GROUP BY buckets ORDER BY buckets')
|
||||
.to match(/^WITH "count_cte" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -114,18 +114,6 @@ RSpec.describe Packages::Package, type: :model do
|
|||
|
||||
expect(subject).to match_array([package1, package2])
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements disabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: false)
|
||||
end
|
||||
|
||||
it 'returns package1 and package2' do
|
||||
expect(projects).to receive(:any?).and_call_original
|
||||
|
||||
expect(subject).to match_array([package1, package2])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
|
|
|
@ -124,6 +124,7 @@ RSpec.describe WikiPage::Meta do
|
|||
|
||||
context 'the slug is already in the DB (but not canonical)' do
|
||||
let_it_be(:slug_record) { create(:wiki_page_slug, wiki_page_meta: meta) }
|
||||
|
||||
let(:slug) { slug_record.slug }
|
||||
let(:query_limit) { 4 }
|
||||
|
||||
|
@ -132,6 +133,7 @@ RSpec.describe WikiPage::Meta do
|
|||
|
||||
context 'the slug is already in the DB (and canonical)' do
|
||||
let_it_be(:slug_record) { create(:wiki_page_slug, :canonical, wiki_page_meta: meta) }
|
||||
|
||||
let(:slug) { slug_record.slug }
|
||||
let(:query_limit) { 4 }
|
||||
|
||||
|
|
|
@ -640,6 +640,7 @@ RSpec.describe WikiPage do
|
|||
let_it_be(:existing_page) { create_wiki_page(title: 'test page') }
|
||||
let_it_be(:directory_page) { create_wiki_page(title: 'parent directory/child page') }
|
||||
let_it_be(:page_with_special_characters) { create_wiki_page(title: 'test+page') }
|
||||
|
||||
let(:untitled_page) { described_class.new(wiki) }
|
||||
|
||||
where(:page, :title, :changed) do
|
||||
|
|
|
@ -299,22 +299,6 @@ RSpec.describe API::MavenPackages do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements enabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'handling all conditions'
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements disabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'handling all conditions'
|
||||
end
|
||||
|
||||
context 'with check_maven_path_first enabled' do
|
||||
before do
|
||||
stub_feature_flags(check_maven_path_first: true)
|
||||
|
@ -346,22 +330,6 @@ RSpec.describe API::MavenPackages do
|
|||
|
||||
it_behaves_like 'processing HEAD requests', instance_level: true
|
||||
|
||||
context 'with maven_packages_group_level_improvements enabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'processing HEAD requests', instance_level: true
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements disabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'processing HEAD requests', instance_level: true
|
||||
end
|
||||
|
||||
context 'with check_maven_path_first enabled' do
|
||||
before do
|
||||
stub_feature_flags(check_maven_path_first: true)
|
||||
|
@ -468,8 +436,7 @@ RSpec.describe API::MavenPackages do
|
|||
|
||||
subject
|
||||
|
||||
status = Feature.enabled?(:maven_packages_group_level_improvements, default_enabled: :yaml) ? :not_found : :forbidden
|
||||
expect(response).to have_gitlab_http_status(status)
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
|
||||
it 'denies download when no private token' do
|
||||
|
@ -594,22 +561,6 @@ RSpec.describe API::MavenPackages do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements enabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'handling all conditions'
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements disabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'handling all conditions'
|
||||
end
|
||||
|
||||
context 'with check_maven_path_first enabled' do
|
||||
before do
|
||||
stub_feature_flags(check_maven_path_first: true)
|
||||
|
@ -639,22 +590,6 @@ RSpec.describe API::MavenPackages do
|
|||
let(:path) { package.maven_metadatum.path }
|
||||
let(:url) { "/groups/#{group.id}/-/packages/maven/#{path}/#{package_file.file_name}" }
|
||||
|
||||
context 'with maven_packages_group_level_improvements enabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'processing HEAD requests'
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements disabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'processing HEAD requests'
|
||||
end
|
||||
|
||||
context 'with check_maven_path_first enabled' do
|
||||
before do
|
||||
stub_feature_flags(check_maven_path_first: true)
|
||||
|
@ -743,22 +678,6 @@ RSpec.describe API::MavenPackages do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements enabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'handling all conditions'
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements disabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'handling all conditions'
|
||||
end
|
||||
|
||||
context 'with check_maven_path_first enabled' do
|
||||
before do
|
||||
stub_feature_flags(check_maven_path_first: true)
|
||||
|
@ -789,22 +708,6 @@ RSpec.describe API::MavenPackages do
|
|||
let(:path) { package.maven_metadatum.path }
|
||||
let(:url) { "/projects/#{project.id}/packages/maven/#{path}/#{package_file.file_name}" }
|
||||
|
||||
context 'with maven_packages_group_level_improvements enabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'processing HEAD requests'
|
||||
end
|
||||
|
||||
context 'with maven_packages_group_level_improvements disabled' do
|
||||
before do
|
||||
stub_feature_flags(maven_packages_group_level_improvements: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'processing HEAD requests'
|
||||
end
|
||||
|
||||
context 'with check_maven_path_first enabled' do
|
||||
before do
|
||||
stub_feature_flags(check_maven_path_first: true)
|
||||
|
|
|
@ -30,39 +30,6 @@ RSpec.describe MemberSerializer do
|
|||
.from(nil).to(true)
|
||||
.and change(group_member, :last_blocked_owner).from(nil).to(false)
|
||||
end
|
||||
|
||||
context "with LastGroupOwnerAssigner query improvements" do
|
||||
it "avoids N+1 database queries for last group owner assignment in MembersPresenter" do
|
||||
group_member = create(:group_member, group: group)
|
||||
control_count = ActiveRecord::QueryRecorder.new { member_last_owner_with_preload([group_member]) }.count
|
||||
group_members = create_list(:group_member, 3, group: group)
|
||||
|
||||
expect { member_last_owner_with_preload(group_members) }.not_to exceed_query_limit(control_count)
|
||||
end
|
||||
|
||||
it "avoids N+1 database queries for last blocked owner assignment in MembersPresenter" do
|
||||
group_member = create(:group_member, group: group)
|
||||
control_count = ActiveRecord::QueryRecorder.new { member_last_blocked_owner_with_preload([group_member]) }.count
|
||||
group_members = create_list(:group_member, 3, group: group)
|
||||
|
||||
expect { member_last_blocked_owner_with_preload(group_members) }.not_to exceed_query_limit(control_count)
|
||||
end
|
||||
|
||||
def member_last_owner_with_preload(members)
|
||||
assigner_with_preload(members)
|
||||
members.map { |m| group.member_last_owner?(m) }
|
||||
end
|
||||
|
||||
def member_last_blocked_owner_with_preload(members)
|
||||
assigner_with_preload(members)
|
||||
members.map { |m| group.member_last_blocked_owner?(m) }
|
||||
end
|
||||
|
||||
def assigner_with_preload(members)
|
||||
MembersPreloader.new(members).preload_all
|
||||
Members::LastGroupOwnerAssigner.new(group, members).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'project member' do
|
||||
|
|