diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 49535021b25..3306808ef4e 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -44b902da883a92ec1f19c760a083f9bf51698e41 +0bdcff0f59fb1bc52eb93e930e53965b19296c99 diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION index 034552a83ee..34aae156b19 100644 --- a/GITLAB_PAGES_VERSION +++ b/GITLAB_PAGES_VERSION @@ -1 +1 @@ -1.30.0 +1.31.0 diff --git a/app/assets/javascripts/design_management/utils/tracking.js b/app/assets/javascripts/design_management/utils/tracking.js index fccb49b574b..37296f5b4ff 100644 --- a/app/assets/javascripts/design_management/utils/tracking.js +++ b/app/assets/javascripts/design_management/utils/tracking.js @@ -1,20 +1,22 @@ import Tracking from '~/tracking'; -import api from '~/api'; +import Api from '~/api'; // Snowplow tracking constants const DESIGN_TRACKING_CONTEXT_SCHEMAS = { VIEW_DESIGN_SCHEMA: 'iglu:com.gitlab/design_management_context/jsonschema/1-0-0', }; -const DESIGN_TRACKING_EVENTS = { + +export const DESIGN_TRACKING_PAGE_NAME = 'projects:issues:design'; + +export const DESIGN_SNOWPLOW_EVENT_TYPES = { VIEW_DESIGN: 'view_design', CREATE_DESIGN: 'create_design', UPDATE_DESIGN: 'update_design', }; -// Usage ping tracking constants -const DESIGN_ACTION = 'design_action'; - -export const DESIGN_TRACKING_PAGE_NAME = 'projects:issues:design'; +export const DESIGN_USAGE_PING_EVENT_TYPES = { + DESIGN_ACTION: 'design_action', +}; /** * Track "design detail" view in Snowplow @@ -25,7 +27,7 @@ export function trackDesignDetailView( designVersion = 1, latestVersion = false, ) { - const eventName = DESIGN_TRACKING_EVENTS.VIEW_DESIGN; + const eventName = DESIGN_SNOWPLOW_EVENT_TYPES.VIEW_DESIGN; Tracking.event(DESIGN_TRACKING_PAGE_NAME, eventName, { label: eventName, @@ -42,16 +44,16 @@ export function trackDesignDetailView( } export function trackDesignCreate() { - return Tracking.event(DESIGN_TRACKING_PAGE_NAME, DESIGN_TRACKING_EVENTS.CREATE_DESIGN); + return Tracking.event(DESIGN_TRACKING_PAGE_NAME, DESIGN_SNOWPLOW_EVENT_TYPES.CREATE_DESIGN); } export function trackDesignUpdate() { - return Tracking.event(DESIGN_TRACKING_PAGE_NAME, DESIGN_TRACKING_EVENTS.UPDATE_DESIGN); + return Tracking.event(DESIGN_TRACKING_PAGE_NAME, DESIGN_SNOWPLOW_EVENT_TYPES.UPDATE_DESIGN); } /** * Track "design detail" view via usage ping */ export function usagePingDesignDetailView() { - api.trackRedisHllUserEvent(DESIGN_ACTION); + Api.trackRedisHllUserEvent(DESIGN_USAGE_PING_EVENT_TYPES.DESIGN_ACTION); } diff --git a/app/assets/javascripts/related_issues/components/related_issues_root.vue b/app/assets/javascripts/related_issues/components/related_issues_root.vue index 6f68b25b6fb..73ea13ddc40 100644 --- a/app/assets/javascripts/related_issues/components/related_issues_root.vue +++ b/app/assets/javascripts/related_issues/components/related_issues_root.vue @@ -204,7 +204,16 @@ export default { onInput({ untouchedRawReferences, touchedReference }) { this.store.addPendingReferences(untouchedRawReferences); - this.inputValue = `${touchedReference}`; + this.formatInput(touchedReference); + }, + formatInput(touchedReference = '') { + const startsWithNumber = String(touchedReference).match(/^[0-9]/) !== null; + + if (startsWithNumber) { + this.inputValue = `#${touchedReference}`; + } else { + this.inputValue = `${touchedReference}`; + } }, onBlur(newValue) { this.processAllReferences(newValue); diff --git a/app/assets/javascripts/sourcegraph/index.js b/app/assets/javascripts/sourcegraph/index.js index 796e90bf08e..487a565b152 100644 --- a/app/assets/javascripts/sourcegraph/index.js +++ b/app/assets/javascripts/sourcegraph/index.js @@ -17,7 +17,7 @@ export default function initSourcegraph() { return; } - const assetsUrl = new URL('/assets/webpack/sourcegraph/', window.location.href); + const assetsUrl = new URL(process.env.SOURCEGRAPH_PUBLIC_PATH, window.location.href); const scriptPath = new URL('scripts/integration.bundle.js', assetsUrl).href; window.SOURCEGRAPH_ASSETS_URL = assetsUrl.href; diff --git a/app/controllers/concerns/workhorse_authorization.rb b/app/controllers/concerns/workhorse_authorization.rb index c1ed5579712..a290ba256b6 100644 --- a/app/controllers/concerns/workhorse_authorization.rb +++ b/app/controllers/concerns/workhorse_authorization.rb @@ -14,7 +14,7 @@ module WorkhorseAuthorization authorized = uploader_class.workhorse_authorize( has_length: false, - maximum_size: Gitlab::CurrentSettings.max_attachment_size.megabytes.to_i) + maximum_size: maximum_size.to_i) render json: authorized rescue SocketError @@ -33,6 +33,10 @@ module WorkhorseAuthorization raise NotImplementedError end + def maximum_size + raise NotImplementedError + end + def file_extension_whitelist ImportExportUploader::EXTENSION_WHITELIST end diff --git a/app/controllers/import/gitlab_groups_controller.rb b/app/controllers/import/gitlab_groups_controller.rb index 99e41190912..f68b76a7b36 100644 --- a/app/controllers/import/gitlab_groups_controller.rb +++ b/app/controllers/import/gitlab_groups_controller.rb @@ -68,4 +68,8 @@ class Import::GitlabGroupsController < ApplicationController def uploader_class ImportExportUploader end + + def maximum_size + Gitlab::CurrentSettings.max_import_size.megabytes + end end diff --git a/app/controllers/import/gitlab_projects_controller.rb b/app/controllers/import/gitlab_projects_controller.rb index a39d1583542..0e6b0af6baf 100644 --- a/app/controllers/import/gitlab_projects_controller.rb +++ b/app/controllers/import/gitlab_projects_controller.rb @@ -49,4 +49,8 @@ class Import::GitlabProjectsController < Import::BaseController def uploader_class ImportExportUploader end + + def maximum_size + Gitlab::CurrentSettings.max_import_size.megabytes + end end diff --git a/app/graphql/resolvers/project_pipeline_statistics_resolver.rb b/app/graphql/resolvers/project_pipeline_statistics_resolver.rb new file mode 100644 index 00000000000..29ab9402f5b --- /dev/null +++ b/app/graphql/resolvers/project_pipeline_statistics_resolver.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Resolvers + class ProjectPipelineStatisticsResolver < BaseResolver + type Types::Ci::AnalyticsType, null: true + + def resolve + weekly_stats = Gitlab::Ci::Charts::WeekChart.new(object) + monthly_stats = Gitlab::Ci::Charts::MonthChart.new(object) + yearly_stats = Gitlab::Ci::Charts::YearChart.new(object) + pipeline_times = Gitlab::Ci::Charts::PipelineTime.new(object) + + { + week_pipelines_labels: weekly_stats.labels, + week_pipelines_totals: weekly_stats.total, + week_pipelines_successful: weekly_stats.success, + month_pipelines_labels: monthly_stats.labels, + month_pipelines_totals: monthly_stats.total, + month_pipelines_successful: monthly_stats.success, + year_pipelines_labels: yearly_stats.labels, + year_pipelines_totals: yearly_stats.total, + year_pipelines_successful: yearly_stats.success, + pipeline_times_labels: pipeline_times.labels, + pipeline_times_values: pipeline_times.pipeline_times + } + end + end +end diff --git a/app/graphql/types/ci/analytics_type.rb b/app/graphql/types/ci/analytics_type.rb new file mode 100644 index 00000000000..c8b12c6a9b8 --- /dev/null +++ b/app/graphql/types/ci/analytics_type.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + class AnalyticsType < BaseObject + graphql_name 'PipelineAnalytics' + + field :week_pipelines_totals, [GraphQL::INT_TYPE], null: true, + description: 'Total weekly pipeline count' + field :week_pipelines_successful, [GraphQL::INT_TYPE], null: true, + description: 'Total weekly successful pipeline count' + field :week_pipelines_labels, [GraphQL::STRING_TYPE], null: true, + description: 'Labels for the weekly pipeline count' + field :month_pipelines_totals, [GraphQL::INT_TYPE], null: true, + description: 'Total monthly pipeline count' + field :month_pipelines_successful, [GraphQL::INT_TYPE], null: true, + description: 'Total monthly successful pipeline count' + field :month_pipelines_labels, [GraphQL::STRING_TYPE], null: true, + description: 'Labels for the monthly pipeline count' + field :year_pipelines_totals, [GraphQL::INT_TYPE], null: true, + description: 'Total yearly pipeline count' + field :year_pipelines_successful, [GraphQL::INT_TYPE], null: true, + description: 'Total yearly successful pipeline count' + field :year_pipelines_labels, [GraphQL::STRING_TYPE], null: true, + description: 'Labels for the yearly pipeline count' + field :pipeline_times_values, [GraphQL::INT_TYPE], null: true, + description: 'Pipeline times' + field :pipeline_times_labels, [GraphQL::STRING_TYPE], null: true, + description: 'Pipeline times labels' + end + end +end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 2e32c0762ee..3d0dd8a1ffd 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -304,6 +304,13 @@ module Types description: 'Terraform states associated with the project', resolver: Resolvers::Terraform::StatesResolver + field :pipeline_analytics, Types::Ci::AnalyticsType, null: true, + description: 'Pipeline analytics', + resolver: Resolvers::ProjectPipelineStatisticsResolver + + field :total_pipeline_duration, GraphQL::INT_TYPE, null: true, + description: 'Total pipeline duration for all of the pipelines in a project' + def label(title:) BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args| LabelsFinder @@ -348,6 +355,10 @@ module Types project.container_repositories.size end + def total_pipeline_duration + object.all_pipelines.total_duration + end + private def project diff --git a/app/models/project.rb b/app/models/project.rb index 69032b3d762..7824f5610d4 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1843,6 +1843,7 @@ class Project < ApplicationRecord wiki.repository.expire_content_cache DetectRepositoryLanguagesWorker.perform_async(id) + ProjectCacheWorker.perform_async(self.id, [], [:repository_size]) # The import assigns iid values on its own, e.g. by re-using GitHub ids. # Flush existing InternalId records for this project for consistency reasons. diff --git a/app/services/issues/clone_service.rb b/app/services/issues/clone_service.rb index a8c0cb05ebe..d018ba235ad 100644 --- a/app/services/issues/clone_service.rb +++ b/app/services/issues/clone_service.rb @@ -4,10 +4,11 @@ module Issues class CloneService < Issuable::Clone::BaseService CloneError = Class.new(StandardError) - def execute(issue, target_project) + def execute(issue, target_project, with_notes: false) @target_project = target_project + @with_notes = with_notes - unless issue.can_clone?(current_user, @target_project) + unless issue.can_clone?(current_user, target_project) raise CloneError, s_('CloneIssue|Cannot clone issue due to insufficient permissions!') end @@ -17,6 +18,8 @@ module Issues super(issue, target_project) + notify_participants + queue_copy_designs new_entity @@ -25,12 +28,14 @@ module Issues private attr_reader :target_project + attr_reader :with_notes def update_new_entity # we don't call `super` because we want to be able to decide whether or not to copy all comments over. update_new_entity_description update_new_entity_attributes copy_award_emoji + copy_notes if with_notes end def update_old_entity @@ -51,7 +56,7 @@ module Issues # Skip creation of system notes for existing attributes of the issue. The system notes of the old # issue are copied over so we don't want to end up with duplicate notes. - CreateService.new(@target_project, @current_user, new_params).execute(skip_system_notes: true) + CreateService.new(target_project, current_user, new_params).execute(skip_system_notes: true) end def queue_copy_designs @@ -66,6 +71,10 @@ module Issues log_error(response.message) if response.error? end + def notify_participants + notification_service.async.issue_cloned(original_entity, new_entity, current_user) + end + def add_note_from SystemNoteService.noteable_cloned(new_entity, target_project, original_entity, current_user, diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb index a2c11cb0a7c..4f40ff5f535 100644 --- a/app/services/issues/update_service.rb +++ b/app/services/issues/update_service.rb @@ -129,13 +129,14 @@ module Issues def clone_issue(issue) target_project = params.delete(:target_clone_project) + with_notes = params.delete(:clone_with_notes) return unless target_project && issue.can_clone?(current_user, target_project) # we've pre-empted this from running in #execute, so let's go ahead and update the Issue now. update(issue) - Issues::CloneService.new(project, current_user).execute(issue, target_project) + Issues::CloneService.new(project, current_user).execute(issue, target_project, with_notes: with_notes) end def create_merge_request_from_quick_action diff --git a/app/workers/concerns/limited_capacity/worker.rb b/app/workers/concerns/limited_capacity/worker.rb index b5a97e49300..9dd8d942146 100644 --- a/app/workers/concerns/limited_capacity/worker.rb +++ b/app/workers/concerns/limited_capacity/worker.rb @@ -73,7 +73,7 @@ module LimitedCapacity raise ensure job_tracker.remove(jid) - report_prometheus_metrics + report_prometheus_metrics(*args) re_enqueue(*args) unless exception end diff --git a/changelogs/unreleased/234002-conan-create-build-info.yml b/changelogs/unreleased/234002-conan-create-build-info.yml new file mode 100644 index 00000000000..773b279e506 --- /dev/null +++ b/changelogs/unreleased/234002-conan-create-build-info.yml @@ -0,0 +1,5 @@ +--- +title: Conan packages show build and commit information when published using CI +merge_request: 49426 +author: +type: fixed diff --git a/changelogs/unreleased/284588-prefix-sourcegraph-url-with-version.yml b/changelogs/unreleased/284588-prefix-sourcegraph-url-with-version.yml new file mode 100644 index 00000000000..942ceb6c577 --- /dev/null +++ b/changelogs/unreleased/284588-prefix-sourcegraph-url-with-version.yml @@ -0,0 +1,5 @@ +--- +title: Make sure Sourcegraph asset always loads successfully +merge_request: 49030 +author: +type: fixed diff --git a/changelogs/unreleased/9421-clone_with_notes-quickaction.yml b/changelogs/unreleased/9421-clone_with_notes-quickaction.yml new file mode 100644 index 00000000000..cee4f4b2d4c --- /dev/null +++ b/changelogs/unreleased/9421-clone_with_notes-quickaction.yml @@ -0,0 +1,6 @@ +--- +title: Implement a /clone_with_notes quick-action to quickly clone an Issue will all + its notes +merge_request: 48539 +author: +type: added diff --git a/changelogs/unreleased/jivanvl-migrate-analytics-graphql-be.yml b/changelogs/unreleased/jivanvl-migrate-analytics-graphql-be.yml new file mode 100644 index 00000000000..46c59383a29 --- /dev/null +++ b/changelogs/unreleased/jivanvl-migrate-analytics-graphql-be.yml @@ -0,0 +1,5 @@ +--- +title: Add CI/CD analytics GraphQL types +merge_request: 49384 +author: +type: added diff --git a/changelogs/unreleased/mk-geo-primary-backfills-checksums.yml b/changelogs/unreleased/mk-geo-primary-backfills-checksums.yml new file mode 100644 index 00000000000..a67b982c4ea --- /dev/null +++ b/changelogs/unreleased/mk-geo-primary-backfills-checksums.yml @@ -0,0 +1,5 @@ +--- +title: 'Geo: Add verification indexes for package files' +merge_request: 47372 +author: +type: added diff --git a/changelogs/unreleased/pages-version-v1-31-0.yml b/changelogs/unreleased/pages-version-v1-31-0.yml new file mode 100644 index 00000000000..027d43709d6 --- /dev/null +++ b/changelogs/unreleased/pages-version-v1-31-0.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade Pages to 1.31.0 +merge_request: 49352 +author: +type: added diff --git a/changelogs/unreleased/sh-update-repo-size-after-import.yml b/changelogs/unreleased/sh-update-repo-size-after-import.yml new file mode 100644 index 00000000000..8ae92fa9711 --- /dev/null +++ b/changelogs/unreleased/sh-update-repo-size-after-import.yml @@ -0,0 +1,5 @@ +--- +title: Update repository size after import +merge_request: 49319 +author: +type: fixed diff --git a/changelogs/unreleased/ss-related-issues-autocomplete.yml b/changelogs/unreleased/ss-related-issues-autocomplete.yml new file mode 100644 index 00000000000..a04d32de43e --- /dev/null +++ b/changelogs/unreleased/ss-related-issues-autocomplete.yml @@ -0,0 +1,5 @@ +--- +title: 'Add ability to type a number in related issues and prepend #' +merge_request: 48952 +author: +type: changed diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index f2315b2a431..1fae590a4d8 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -553,6 +553,9 @@ Gitlab.ee do Settings.cron_jobs['adjourned_projects_deletion_cron_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['adjourned_projects_deletion_cron_worker']['cron'] ||= '0 4 * * *' Settings.cron_jobs['adjourned_projects_deletion_cron_worker']['job_class'] = 'AdjournedProjectsDeletionCronWorker' + Settings.cron_jobs['geo_verification_cron_worker'] ||= Settingslogic.new({}) + Settings.cron_jobs['geo_verification_cron_worker']['cron'] ||= '* * * * *' + Settings.cron_jobs['geo_verification_cron_worker']['job_class'] ||= 'Geo::VerificationCronWorker' Settings.cron_jobs['geo_file_download_dispatch_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['geo_file_download_dispatch_worker']['cron'] ||= '*/1 * * * *' Settings.cron_jobs['geo_file_download_dispatch_worker']['job_class'] ||= 'Geo::FileDownloadDispatchWorker' diff --git a/config/webpack.config.js b/config/webpack.config.js index c193e0d6148..42e27ea1668 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -29,9 +29,18 @@ const WEBPACK_MEMORY_TEST = const NO_COMPRESSION = process.env.NO_COMPRESSION && process.env.NO_COMPRESSION !== 'false'; const NO_SOURCEMAPS = process.env.NO_SOURCEMAPS && process.env.NO_SOURCEMAPS !== 'false'; +const WEBPACK_OUTPUT_PATH = path.join(ROOT_PATH, 'public/assets/webpack'); +const WEBPACK_PUBLIC_PATH = '/assets/webpack/'; +const SOURCEGRAPH_PACKAGE = '@sourcegraph/code-host-integration'; + const VUE_VERSION = require('vue/package.json').version; const VUE_LOADER_VERSION = require('vue-loader/package.json').version; const WEBPACK_VERSION = require('webpack/package.json').version; +const SOURCEGRAPH_VERSION = require(path.join(SOURCEGRAPH_PACKAGE, 'package.json')).version; + +const SOURCEGRAPH_PATH = path.join('sourcegraph', SOURCEGRAPH_VERSION, '/'); +const SOURCEGRAPH_OUTPUT_PATH = path.join(WEBPACK_OUTPUT_PATH, SOURCEGRAPH_PATH); +const SOURCEGRAPH_PUBLIC_PATH = path.join(WEBPACK_PUBLIC_PATH, SOURCEGRAPH_PATH); const devtool = IS_PRODUCTION ? 'source-map' : 'cheap-module-eval-source-map'; @@ -143,7 +152,7 @@ if (VENDOR_DLL && !IS_PRODUCTION) { dll = { manifestPath: path.join(dllCachePath, 'vendor.dll.manifest.json'), cacheFrom: dllCachePath, - cacheTo: path.join(ROOT_PATH, `public/assets/webpack/dll.${dllHash}/`), + cacheTo: path.join(WEBPACK_OUTPUT_PATH, `dll.${dllHash}/`), publicPath: `dll.${dllHash}/vendor.dll.bundle.js`, exists: null, }; @@ -157,8 +166,8 @@ module.exports = { entry: generateEntries, output: { - path: path.join(ROOT_PATH, 'public/assets/webpack'), - publicPath: '/assets/webpack/', + path: WEBPACK_OUTPUT_PATH, + publicPath: WEBPACK_PUBLIC_PATH, filename: IS_PRODUCTION ? '[name].[contenthash:8].bundle.js' : '[name].bundle.js', chunkFilename: IS_PRODUCTION ? '[name].[contenthash:8].chunk.js' : '[name].chunk.js', globalObject: 'this', // allow HMR and web workers to play nice @@ -449,11 +458,11 @@ module.exports = { new CopyWebpackPlugin([ { from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/cmaps/'), - to: path.join(ROOT_PATH, 'public/assets/webpack/cmaps/'), + to: path.join(WEBPACK_OUTPUT_PATH, 'cmaps/'), }, { - from: path.join(ROOT_PATH, 'node_modules/@sourcegraph/code-host-integration/'), - to: path.join(ROOT_PATH, 'public/assets/webpack/sourcegraph/'), + from: path.join(ROOT_PATH, 'node_modules', SOURCEGRAPH_PACKAGE, '/'), + to: SOURCEGRAPH_OUTPUT_PATH, ignore: ['package.json'], }, { @@ -461,7 +470,7 @@ module.exports = { ROOT_PATH, 'node_modules/@gitlab/visual-review-tools/dist/visual_review_toolbar.js', ), - to: path.join(ROOT_PATH, 'public/assets/webpack'), + to: WEBPACK_OUTPUT_PATH, }, ]), @@ -555,6 +564,8 @@ module.exports = { 'process.env.IS_EE': JSON.stringify(IS_EE), // This one is used to check against "EE" properly in application code IS_EE: IS_EE ? 'window.gon && window.gon.ee' : JSON.stringify(false), + // This is used by Sourcegraph because these assets are loaded dnamically + 'process.env.SOURCEGRAPH_PUBLIC_PATH': JSON.stringify(SOURCEGRAPH_PUBLIC_PATH), }), /* Pikaday has a optional dependency to moment. diff --git a/db/migrate/20201201033202_add_verification_indexes_for_package_files.rb b/db/migrate/20201201033202_add_verification_indexes_for_package_files.rb new file mode 100644 index 00000000000..b7f55101682 --- /dev/null +++ b/db/migrate/20201201033202_add_verification_indexes_for_package_files.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class AddVerificationIndexesForPackageFiles < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + PENDING_VERIFICATION_INDEX_NAME = "packages_packages_pending_verification" + FAILED_VERIFICATION_INDEX_NAME = "packages_packages_failed_verification" + NEEDS_VERIFICATION_INDEX_NAME = "packages_packages_needs_verification" + + disable_ddl_transaction! + + def up + add_concurrent_index :packages_package_files, :verified_at, where: "(verification_state = 0)", order: { verified_at: 'ASC NULLS FIRST' }, name: PENDING_VERIFICATION_INDEX_NAME + add_concurrent_index :packages_package_files, :verification_retry_at, where: "(verification_state = 3)", order: { verification_retry_at: 'ASC NULLS FIRST' }, name: FAILED_VERIFICATION_INDEX_NAME + add_concurrent_index :packages_package_files, :verification_state, where: "(verification_state = 0 OR verification_state = 3)", name: NEEDS_VERIFICATION_INDEX_NAME + end + + def down + remove_concurrent_index_by_name :packages_package_files, PENDING_VERIFICATION_INDEX_NAME + remove_concurrent_index_by_name :packages_package_files, FAILED_VERIFICATION_INDEX_NAME + remove_concurrent_index_by_name :packages_package_files, NEEDS_VERIFICATION_INDEX_NAME + end +end diff --git a/db/schema_migrations/20201201033202 b/db/schema_migrations/20201201033202 new file mode 100644 index 00000000000..a061dc5f404 --- /dev/null +++ b/db/schema_migrations/20201201033202 @@ -0,0 +1 @@ +418481f8281f8908740d3a8378b420f4d83853aab139b3401f7e410fc97d2488 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index fdd3bcc5789..301597953ab 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -22751,6 +22751,12 @@ CREATE UNIQUE INDEX one_canonical_wiki_page_slug_per_metadata ON wiki_page_slugs CREATE INDEX package_name_index ON packages_packages USING btree (name); +CREATE INDEX packages_packages_failed_verification ON packages_package_files USING btree (verification_retry_at NULLS FIRST) WHERE (verification_state = 3); + +CREATE INDEX packages_packages_needs_verification ON packages_package_files USING btree (verification_state) WHERE ((verification_state = 0) OR (verification_state = 3)); + +CREATE INDEX packages_packages_pending_verification ON packages_package_files USING btree (verified_at NULLS FIRST) WHERE (verification_state = 0); + CREATE INDEX partial_index_ci_builds_on_scheduled_at_with_scheduled_jobs ON ci_builds USING btree (scheduled_at) WHERE ((scheduled_at IS NOT NULL) AND ((type)::text = 'Ci::Build'::text) AND ((status)::text = 'scheduled'::text)); CREATE INDEX partial_index_deployments_for_legacy_successful_deployments ON deployments USING btree (id) WHERE ((finished_at IS NULL) AND (status = 2)); diff --git a/doc/.vale/gitlab/AlertBoxCaution.yml b/doc/.vale/gitlab/AlertBoxCaution.yml deleted file mode 100644 index 49d4dc62ab5..00000000000 --- a/doc/.vale/gitlab/AlertBoxCaution.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -# Error: gitlab.AlertBoxCaution -# -# Makes sure CAUTION: alert boxes follow standard formatting. -# -# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles -extends: substitution -message: "CAUTION: alert boxes must be of the format 'CAUTION: **Caution:**'. 'Caution' can be replaced with 'Warning' or 'Important'." -link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#alert-boxes -level: warning -nonword: true -scope: raw -swap: - 'CAUTION: *?\*\*.*\*\*': 'CAUTION: \*\*(?:Caution|Warning|Important):\*\*' diff --git a/doc/.vale/gitlab/AlertBoxDanger.yml b/doc/.vale/gitlab/AlertBoxDanger.yml deleted file mode 100644 index 2589d34614c..00000000000 --- a/doc/.vale/gitlab/AlertBoxDanger.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -# Error: gitlab.AlertBoxDanger -# -# Makes sure DANGER: alert boxes follow standard formatting. -# -# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles -extends: substitution -message: "DANGER: alert boxes must be of the format 'DANGER: **Warning:**'. 'Warning' can be replaced with 'Important', 'Deprecated', or 'Required'." -link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#alert-boxes -level: error -nonword: true -scope: raw -swap: - 'DANGER: *?\*\*.*\*\*': 'DANGER: \*\*(?:Warning|Important|Deprecated|Required):\*\*' diff --git a/doc/.vale/gitlab/AlertBoxNoteTip.yml b/doc/.vale/gitlab/AlertBoxNoteTip.yml deleted file mode 100644 index 62bd89f7ca6..00000000000 --- a/doc/.vale/gitlab/AlertBoxNoteTip.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -# Error: gitlab.AlertBoxNoteTip -# -# Makes sure NOTE: and TIP: alert boxes follow standard formatting. -# -# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles -extends: substitution -message: "NOTE: and TIP: alert boxes must be of the format 'NOTE:' or 'TIP: **Tip:**" -link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#alert-boxes -level: warning -nonword: true -scope: raw -swap: - 'NOTE: *?\*\*.*\*\*': 'NOTE: \*\*Note:\*\*' - 'TIP: *?\*\*.*\*\*': 'TIP: \*\*Tip:\*\*' diff --git a/doc/.vale/gitlab/AlertBoxStyle.yml b/doc/.vale/gitlab/AlertBoxStyle.yml deleted file mode 100644 index d15757d38fc..00000000000 --- a/doc/.vale/gitlab/AlertBoxStyle.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -# Error: gitlab.AlertBoxStyle -# -# Makes sure alert boxes follow standard formatting. -# -# Checks for 2 formatting issues: -# - Alert boxes with the note text on the same line -# - Alert boxes using blockquote formatting, like "> **Note:**" -# -# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles -extends: existence -message: 'Alert box "%s" must use the formatting in the style guide.' -link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#alert-boxes -level: error -scope: raw -raw: - - '(\n(NOTE|TIP|CAUTION|DANGER): \*\*.*\*\*.+)|' - - '((\n[> ]*(\*){1,2}(NOTE|Note|note|TIP|Tip|tip|CAUTION|Caution|caution|DANGER|Danger|danger):(\*){1,2}))' diff --git a/doc/administration/geo/disaster_recovery/index.md b/doc/administration/geo/disaster_recovery/index.md index c7aaded2f91..be84b260127 100644 --- a/doc/administration/geo/disaster_recovery/index.md +++ b/doc/administration/geo/disaster_recovery/index.md @@ -134,7 +134,7 @@ Note the following when promoting a secondary: 1. Promote the **secondary** node to the **primary** node. - DANGER: **Warning:** + WARNING: In GitLab 13.2 and 13.3, promoting a secondary node to a primary while the secondary is paused fails. Do not pause replication before promoting a secondary. If the node is paused, be sure to resume before promoting. This @@ -174,7 +174,7 @@ conjunction with multiple servers, as it can only perform changes on a **secondary** with only a single machine. Instead, you must do this manually. -DANGER: **Warning:** +WARNING: In GitLab 13.2 and 13.3, promoting a secondary node to a primary while the secondary is paused fails. Do not pause replication before promoting a secondary. If the node is paused, be sure to resume before promoting. This diff --git a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md index 2c5cbb32903..6fe4030ff54 100644 --- a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md +++ b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md @@ -227,7 +227,7 @@ conjunction with multiple servers, as it can only perform changes on a **secondary** with only a single machine. Instead, you must do this manually. -DANGER: **Warning:** +WARNING: In GitLab 13.2 and 13.3, promoting a secondary node to a primary while the secondary is paused fails. Do not pause replication before promoting a secondary. If the node is paused, be sure to resume before promoting. This diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md index aac4411637c..408dd5e12df 100644 --- a/doc/administration/geo/index.md +++ b/doc/administration/geo/index.md @@ -201,7 +201,7 @@ For information on how to update your Geo nodes to the latest GitLab version, se > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35913) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2. -DANGER: **Warning:** +WARNING: In GitLab 13.2 and 13.3, promoting a secondary node to a primary while the secondary is paused fails. Do not pause replication before promoting a secondary. If the node is paused, be sure to resume before promoting. This diff --git a/doc/administration/geo/replication/datatypes.md b/doc/administration/geo/replication/datatypes.md index df9ddf6818a..0d2922c3347 100644 --- a/doc/administration/geo/replication/datatypes.md +++ b/doc/administration/geo/replication/datatypes.md @@ -163,7 +163,7 @@ To enable, such as for package file replication: Feature.enable(:geo_package_file_replication) ``` -DANGER: **Warning:** +WARNING: Features not on this list, or with **No** in the **Replicated** column, are not replicated on the **secondary** node. Failing over without manually replicating data from those features will cause the data to be **lost**. diff --git a/doc/administration/geo/replication/version_specific_updates.md b/doc/administration/geo/replication/version_specific_updates.md index 9701bc5d647..0d8eba555ab 100644 --- a/doc/administration/geo/replication/version_specific_updates.md +++ b/doc/administration/geo/replication/version_specific_updates.md @@ -28,7 +28,7 @@ DROP SERVER gitlab_secondary CASCADE; DROP EXTENSION IF EXISTS postgres_fdw; ``` -DANGER: **Warning:** +WARNING: In GitLab 13.3, promoting a secondary node to a primary while the secondary is paused fails. Do not pause replication before promoting a secondary. If the node is paused, be sure to resume before promoting. To avoid this issue, @@ -85,7 +85,7 @@ sudo touch /etc/gitlab/disable-postgresql-upgrade ## Updating to GitLab 12.7 -DANGER: **Warning:** +WARNING: Only upgrade to GitLab 12.7.5 or later. Do not upgrade to versions 12.7.0 through 12.7.4 because there is [an initialization order bug](https://gitlab.com/gitlab-org/gitlab/-/issues/199672) that causes Geo @@ -145,7 +145,7 @@ sudo touch /etc/gitlab/disable-postgresql-upgrade ## Updating to GitLab 12.3 -DANGER: **Warning:** +WARNING: If the existing PostgreSQL server version is 9.6.x, it is recommended to upgrade to GitLab 12.4 or later. By default, GitLab 12.3 attempts to update the embedded PostgreSQL server from 9.6 to 10.9. In certain circumstances, it will @@ -159,7 +159,7 @@ For the recommended procedure, see the ## Updating to GitLab 12.2 -DANGER: **Warning:** +WARNING: If the existing PostgreSQL server version is 9.6.x, it is recommended to upgrade to GitLab 12.4 or later. By default, GitLab 12.2 attempts to update the embedded PostgreSQL server from 9.6 to 10.9. In certain circumstances, it will @@ -189,7 +189,7 @@ The restart avoids a version mismatch when PostgreSQL tries to load the FDW exte ## Updating to GitLab 12.1 -DANGER: **Warning:** +WARNING: If the existing PostgreSQL server version is 9.6.x, it is recommended to upgrade to GitLab 12.4 or later. By default, GitLab 12.1 attempts to update the embedded PostgreSQL server from 9.6 to 10.9. In certain circumstances, it will diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md index a717f126375..a7385b88feb 100644 --- a/doc/administration/gitaly/index.md +++ b/doc/administration/gitaly/index.md @@ -122,7 +122,7 @@ The following list depicts the network architecture of Gitaly: - Authentication is done through a static token which is shared among the Gitaly and GitLab Rails nodes. -DANGER: **Warning:** +WARNING: Gitaly servers must not be exposed to the public internet as Gitaly's network traffic is unencrypted by default. The use of firewall is highly recommended to restrict access to the Gitaly server. Another option is to [use TLS](#enable-tls-support). @@ -451,7 +451,7 @@ server (with `gitaly_address`) unless you setup with special When you tail the Gitaly logs on your Gitaly server, you should see requests coming in. One sure way to trigger a Gitaly request is to clone a repository from GitLab over HTTP or HTTPS. -DANGER: **Warning:** +WARNING: If you have [server hooks](../server_hooks.md) configured, either per repository or globally, you must move these to the Gitaly servers. If you have multiple Gitaly servers, copy your server hooks to all Gitaly servers. diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md index 15d672d3885..5d07e7d1b26 100644 --- a/doc/administration/job_artifacts.md +++ b/doc/administration/job_artifacts.md @@ -103,7 +103,7 @@ If you configure GitLab to store artifacts on object storage, you may also want [eliminate local disk usage for job logs](job_logs.md#prevent-local-disk-usage). In both cases, job logs are archived and moved to object storage when the job completes. -DANGER: **Warning:** +WARNING: In a multi-server setup you must use one of the options to [eliminate local disk usage for job logs](job_logs.md#prevent-local-disk-usage), or job logs could be lost. diff --git a/doc/administration/job_logs.md b/doc/administration/job_logs.md index b6fc27674fa..7af167de4ad 100644 --- a/doc/administration/job_logs.md +++ b/doc/administration/job_logs.md @@ -121,7 +121,7 @@ job output in the UI is empty. For example, to delete all job logs older than 60 days, run the following from a shell in your GitLab instance: -DANGER: **Warning:** +WARNING: This command permanently deletes the log files and is irreversible. ```shell diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md index e3453698da6..e76e81c6499 100644 --- a/doc/administration/monitoring/performance/grafana_configuration.md +++ b/doc/administration/monitoring/performance/grafana_configuration.md @@ -113,7 +113,7 @@ If you require access to your old Grafana data but don't meet one of these crite 1. [Exporting the dashboards](https://grafana.com/docs/grafana/latest/reference/export_import/#exporting-a-dashboard) you need. 1. Refreshing the data and [re-importing your dashboards](https://grafana.com/docs/grafana/latest/reference/export_import/#importing-a-dashboard). -DANGER: **Warning:** +WARNING: These actions pose a temporary vulnerability while your old Grafana data is in use. Deciding to take any of these actions should be weighed carefully with your need to access existing data and dashboards. diff --git a/doc/administration/operations/moving_repositories.md b/doc/administration/operations/moving_repositories.md index a62dee813f2..ac1ce851b6a 100644 --- a/doc/administration/operations/moving_repositories.md +++ b/doc/administration/operations/moving_repositories.md @@ -48,7 +48,7 @@ We look at three scenarios: - The target directory contains an outdated copy of the repositories. - How to deal with thousands of repositories. -DANGER: **Warning:** +WARNING: Each of the approaches we list can or does overwrite data in the target directory `/mnt/gitlab/repositories`. Do not mix up the source and the target. @@ -94,7 +94,7 @@ If you want to compress the data before it goes over the network ### The target directory contains an outdated copy of the repositories: use `rsync` -DANGER: **Warning:** +WARNING: Using `rsync` to migrate Git data can cause data loss and repository corruption. [These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422). @@ -115,7 +115,7 @@ If you want to see progress, replace `-a` with `-av`. #### Single `rsync` to another server -DANGER: **Warning:** +WARNING: Using `rsync` to migrate Git data can cause data loss and repository corruption. [These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422). @@ -129,7 +129,7 @@ sudo -u git sh -c 'rsync -a --delete /var/opt/gitlab/git-data/repositories/. \ ### Thousands of Git repositories: use one `rsync` per repository -DANGER: **Warning:** +WARNING: Using `rsync` to migrate Git data can cause data loss and repository corruption. [These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422). @@ -150,7 +150,7 @@ longer exist at the source.** #### Parallel `rsync` for all repositories known to GitLab -DANGER: **Warning:** +WARNING: Using `rsync` to migrate Git data can cause data loss and repository corruption. [These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422). @@ -211,7 +211,7 @@ cat /home/git/transfer-logs/* | sort | uniq -u |\ #### Parallel `rsync` only for repositories with recent activity -DANGER: **Warning:** +WARNING: Using `rsync` to migrate Git data can cause data loss and repository corruption. [These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422). diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md index 667595bc1f9..8443a781ef1 100644 --- a/doc/administration/packages/container_registry.md +++ b/doc/administration/packages/container_registry.md @@ -485,7 +485,7 @@ you can pull from the Container Registry, but you cannot push. [`--dryrun`](https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html) flag and run the command. - DANGER: **Warning:** + WARNING: The [`--delete`](https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html) flag deletes files that exist in the destination but not in the source. If you swap the source and destination, all data in the Registry is deleted. @@ -837,7 +837,7 @@ understand the implications. > [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/3097) in Omnibus GitLab 11.10. -DANGER: **Warning:** +WARNING: This is a destructive operation. The GitLab Container Registry follows the same default workflow as Docker Distribution: diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md index 3baf66756f0..13dd742b53c 100644 --- a/doc/administration/pages/index.md +++ b/doc/administration/pages/index.md @@ -375,7 +375,7 @@ Pages access control is disabled by default. To enable it: 1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure). 1. Users can now configure it in their [projects' settings](../../user/project/pages/pages_access_control.md). -NOTE: **Important:** +NOTE: For this setting to be effective with multi-node setups, it has to be applied to all the App nodes and Sidekiq nodes. @@ -431,7 +431,7 @@ For Omnibus, this is fixed by [installing a custom CA in Omnibus GitLab](https:/ > [Introduced](https://gitlab.com/gitlab-org/gitlab-pages/-/merge_requests/392) in GitLab 13.7. -DANGER: **Warning:** +WARNING: These are advanced settings. The recommended default values are set inside GitLab Pages. You should change these settings only if absolutely necessary. Use extreme caution. @@ -575,7 +575,7 @@ your main application server. To configure GitLab Pages on a separate server: -DANGER: **Warning:** +WARNING: The following procedure includes steps to back up and edit the `gitlab-secrets.json` file. This file contains secrets that control database encryption. Proceed with caution. diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md index e6e3128eeef..26381434ad4 100644 --- a/doc/administration/raketasks/maintenance.md +++ b/doc/administration/raketasks/maintenance.md @@ -272,7 +272,7 @@ clear it. To clear all exclusive leases: -DANGER: **Warning:** +WARNING: Don't run it while GitLab or Sidekiq is running ```shell diff --git a/doc/administration/raketasks/storage.md b/doc/administration/raketasks/storage.md index 68874c04043..6f7bd21ca80 100644 --- a/doc/administration/raketasks/storage.md +++ b/doc/administration/raketasks/storage.md @@ -74,7 +74,7 @@ To have a summary and then a list of projects and their attachments using hashed ## Migrate to hashed storage -DANGER: **Deprecated:** +WARNING: In GitLab 13.0, [hashed storage](../repository_storage_types.md#hashed-storage) is enabled by default and the legacy storage is deprecated. Support for legacy storage will be removed in GitLab 14.0. If you're on GitLab @@ -123,7 +123,7 @@ commands below that helps you inspect projects and attachments in both legacy an ## Rollback from hashed storage to legacy storage -DANGER: **Deprecated:** +WARNING: In GitLab 13.0, [hashed storage](../repository_storage_types.md#hashed-storage) is enabled by default and the legacy storage is deprecated. Support for legacy storage will be removed in GitLab 14.0. If you're on GitLab diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md index f43b5cd20bf..6ec43a8ce06 100644 --- a/doc/administration/repository_storage_types.md +++ b/doc/administration/repository_storage_types.md @@ -117,7 +117,7 @@ The output includes the project ID and the project name: > [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/1606) in GitLab 12.1. -DANGER: **Warning:** +WARNING: Do not run `git prune` or `git gc` in pool repositories! This can cause data loss in "real" repositories that depend on the pool in question. @@ -179,7 +179,7 @@ LFS objects are also [S3 compatible](lfs/index.md#storing-lfs-objects-in-remote- ## Legacy storage -NOTE: **Deprecated:** +WARNING: In GitLab 13.0, hashed storage is enabled by default and the legacy storage is deprecated. If you haven't migrated yet, check the [migration instructions](raketasks/storage.md#migrate-to-hashed-storage). diff --git a/doc/administration/snippets/index.md b/doc/administration/snippets/index.md index 5a1b8666ff7..9bc9ebc8473 100644 --- a/doc/administration/snippets/index.md +++ b/doc/administration/snippets/index.md @@ -29,7 +29,7 @@ This setting is not available through the [Admin Area settings](../../user/admin In order to configure this setting, use either the Rails console or the [Application settings API](../../api/settings.md). -NOTE: **IMPORTANT:** +NOTE: The value of the limit **must** be in bytes. #### Through the Rails console diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 7b05391f0b6..6697e3e327f 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -15502,6 +15502,63 @@ type Pipeline { userPermissions: PipelinePermissions! } +type PipelineAnalytics { + """ + Labels for the monthly pipeline count + """ + monthPipelinesLabels: [String!] + + """ + Total monthly successful pipeline count + """ + monthPipelinesSuccessful: [Int!] + + """ + Total monthly pipeline count + """ + monthPipelinesTotals: [Int!] + + """ + Pipeline times labels + """ + pipelineTimesLabels: [String!] + + """ + Pipeline times + """ + pipelineTimesValues: [Int!] + + """ + Labels for the weekly pipeline count + """ + weekPipelinesLabels: [String!] + + """ + Total weekly successful pipeline count + """ + weekPipelinesSuccessful: [Int!] + + """ + Total weekly pipeline count + """ + weekPipelinesTotals: [Int!] + + """ + Labels for the yearly pipeline count + """ + yearPipelinesLabels: [String!] + + """ + Total yearly successful pipeline count + """ + yearPipelinesSuccessful: [Int!] + + """ + Total yearly pipeline count + """ + yearPipelinesTotals: [Int!] +} + """ Autogenerated input type of PipelineCancel """ @@ -16936,6 +16993,11 @@ type Project { iid: ID! ): Pipeline + """ + Pipeline analytics + """ + pipelineAnalytics: PipelineAnalytics + """ Build pipelines of the project """ @@ -17347,6 +17409,11 @@ type Project { last: Int ): TerraformStateConnection + """ + Total pipeline duration for all of the pipelines in a project + """ + totalPipelineDuration: Int + """ Permissions for the current user on the resource """ diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index fcefb27c229..fafc1385709 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -46054,6 +46054,261 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "PipelineAnalytics", + "description": null, + "fields": [ + { + "name": "monthPipelinesLabels", + "description": "Labels for the monthly pipeline count", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "monthPipelinesSuccessful", + "description": "Total monthly successful pipeline count", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "monthPipelinesTotals", + "description": "Total monthly pipeline count", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "pipelineTimesLabels", + "description": "Pipeline times labels", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "pipelineTimesValues", + "description": "Pipeline times", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "weekPipelinesLabels", + "description": "Labels for the weekly pipeline count", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "weekPipelinesSuccessful", + "description": "Total weekly successful pipeline count", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "weekPipelinesTotals", + "description": "Total weekly pipeline count", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "yearPipelinesLabels", + "description": "Labels for the yearly pipeline count", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "yearPipelinesSuccessful", + "description": "Total yearly successful pipeline count", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "yearPipelinesTotals", + "description": "Total yearly pipeline count", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "PipelineCancelInput", @@ -49630,6 +49885,20 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "pipelineAnalytics", + "description": "Pipeline analytics", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "PipelineAnalytics", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "pipelines", "description": "Build pipelines of the project", @@ -50620,6 +50889,20 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "totalPipelineDuration", + "description": "Total pipeline duration for all of the pipelines in a project", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "userPermissions", "description": "Permissions for the current user on the resource", diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index b6b80b53bb4..1bb173bbed3 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -2402,6 +2402,22 @@ Information about pagination in a connection.. | `user` | User | Pipeline user | | `userPermissions` | PipelinePermissions! | Permissions for the current user on the resource | +### PipelineAnalytics + +| Field | Type | Description | +| ----- | ---- | ----------- | +| `monthPipelinesLabels` | String! => Array | Labels for the monthly pipeline count | +| `monthPipelinesSuccessful` | Int! => Array | Total monthly successful pipeline count | +| `monthPipelinesTotals` | Int! => Array | Total monthly pipeline count | +| `pipelineTimesLabels` | String! => Array | Pipeline times labels | +| `pipelineTimesValues` | Int! => Array | Pipeline times | +| `weekPipelinesLabels` | String! => Array | Labels for the weekly pipeline count | +| `weekPipelinesSuccessful` | Int! => Array | Total weekly successful pipeline count | +| `weekPipelinesTotals` | Int! => Array | Total weekly pipeline count | +| `yearPipelinesLabels` | String! => Array | Labels for the yearly pipeline count | +| `yearPipelinesSuccessful` | Int! => Array | Total yearly successful pipeline count | +| `yearPipelinesTotals` | Int! => Array | Total yearly pipeline count | + ### PipelineCancelPayload Autogenerated return type of PipelineCancel. @@ -2505,6 +2521,7 @@ Autogenerated return type of PipelineRetry. | `packages` | PackageConnection | Packages of the project | | `path` | String! | Path of the project | | `pipeline` | Pipeline | Build pipeline of the project | +| `pipelineAnalytics` | PipelineAnalytics | Pipeline analytics | | `pipelines` | PipelineConnection | Build pipelines of the project | | `printingMergeRequestLinkEnabled` | Boolean | Indicates if a link to create or view a merge request should display after a push to Git repositories of the project from the command line | | `projectMembers` | MemberInterfaceConnection | Members of the project | @@ -2535,6 +2552,7 @@ Autogenerated return type of PipelineRetry. | `suggestionCommitMessage` | String | The commit message used to apply merge request suggestions | | `tagList` | String | List of project topics (not Git tags) | | `terraformStates` | TerraformStateConnection | Terraform states associated with the project | +| `totalPipelineDuration` | Int | Total pipeline duration for all of the pipelines in a project | | `userPermissions` | ProjectPermissions! | Permissions for the current user on the resource | | `visibility` | String | Visibility of the project | | `vulnerabilities` | VulnerabilityConnection | Vulnerabilities reported on the project | diff --git a/doc/api/issues.md b/doc/api/issues.md index c962422ae0f..3157acc5d08 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -16,7 +16,7 @@ are paginated. Read more on [pagination](README.md#pagination). -DANGER: **Deprecated:** +WARNING: The `reference` attribute in responses is deprecated in favor of `references`. Introduced in [GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20354). @@ -197,7 +197,7 @@ the `health_status` parameter: ] ``` -DANGER: **Deprecated:** +WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. @@ -375,7 +375,7 @@ the `health_status` parameter: ] ``` -DANGER: **Deprecated:** +WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. NOTE: @@ -558,7 +558,7 @@ the `health_status` parameter: ] ``` -DANGER: **Deprecated:** +WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. NOTE: @@ -716,11 +716,11 @@ the `epic` property: } ``` -DANGER: **Deprecated:** +WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. -DANGER: **Deprecated:** +WARNING: The `epic_iid` attribute is deprecated, and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157). Please use `iid` of the `epic` attribute instead. @@ -878,10 +878,10 @@ property: ] ``` -DANGER: **Deprecated:** +WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. -DANGER: **Deprecated:** +WARNING: The `epic_iid` attribute is deprecated and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157). Please use `iid` of the `epic` attribute instead. @@ -1006,7 +1006,7 @@ the `health_status` parameter: ] ``` -DANGER: **Deprecated:** +WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. NOTE: @@ -1163,7 +1163,7 @@ NOTE: The `closed_by` attribute was [introduced in GitLab 10.6](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042). This value is only present for issues closed after GitLab 10.6 and if the user account that closed the issue still exists. -DANGER: **Deprecated:** +WARNING: `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. ## Delete an issue @@ -1324,7 +1324,7 @@ the `health_status` parameter: ] ``` -DANGER: **Deprecated:** +WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. NOTE: @@ -1433,7 +1433,7 @@ the `weight` parameter: } ``` -DANGER: **Deprecated:** +WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. NOTE: @@ -1623,7 +1623,7 @@ Example response: } ``` -DANGER: **Deprecated:** +WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. NOTE: diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md index 92aef4156cb..88c92c9bead 100644 --- a/doc/ci/docker/using_docker_build.md +++ b/doc/ci/docker/using_docker_build.md @@ -103,7 +103,7 @@ image in privileged mode. CI builds, follow the `docker-compose` [installation instructions](https://docs.docker.com/compose/install/). -DANGER: **Warning:** +WARNING: By enabling `--docker-privileged`, you are effectively disabling all of the security mechanisms of containers and exposing your host to privilege escalation which can lead to container breakout. For more information, check diff --git a/doc/ci/pipelines/job_artifacts.md b/doc/ci/pipelines/job_artifacts.md index 44c0b774864..56e9b285e3c 100644 --- a/doc/ci/pipelines/job_artifacts.md +++ b/doc/ci/pipelines/job_artifacts.md @@ -427,7 +427,7 @@ information in the UI. ## Erasing artifacts -DANGER: **Warning:** +WARNING: This is a destructive action that leads to data loss. Use with caution. You can erase a single job via the UI, which also removes the job's diff --git a/doc/ci/triggers/README.md b/doc/ci/triggers/README.md index 22dbbbf689a..35dec43dbb4 100644 --- a/doc/ci/triggers/README.md +++ b/doc/ci/triggers/README.md @@ -32,7 +32,7 @@ This also applies when using the `pipelines` or `triggers` keywords with the leg A unique trigger token can be obtained when [adding a new trigger](#adding-a-new-trigger). -DANGER: **Warning:** +WARNING: Passing plain text tokens in public projects is a security issue. Potential attackers can impersonate the user that exposed their trigger token publicly in their `.gitlab-ci.yml` file. Use [variables](../variables/README.md#gitlab-cicd-environment-variables) diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index ae5c1f7945c..da9404421fb 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -4332,13 +4332,13 @@ The following keywords are deprecated. ### Globally-defined `types` -DANGER: **Deprecated:** +WARNING: `types` is deprecated, and could be removed in a future release. Use [`stages`](#stages) instead. ### Job-defined `type` -DANGER: **Deprecated:** +WARNING: `type` is deprecated, and could be removed in one of the future releases. Use [`stage`](#stage) instead. diff --git a/doc/development/chaos_endpoints.md b/doc/development/chaos_endpoints.md index 02e88a4f5c7..b3e655e8873 100644 --- a/doc/development/chaos_endpoints.md +++ b/doc/development/chaos_endpoints.md @@ -24,7 +24,7 @@ Currently, there are four endpoints for simulating the following conditions: For obvious reasons, these endpoints are not enabled by default on `production`. They are enabled by default on **development** environments. -DANGER: **Warning:** +WARNING: It is required that you secure access to the chaos endpoints using a secret token. You should not enable them in production unless you absolutely know what you're doing. diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md index d3a498a9b6f..b9a9efea836 100644 --- a/doc/development/contributing/index.md +++ b/doc/development/contributing/index.md @@ -37,7 +37,7 @@ Report suspected security vulnerabilities in private to `support@gitlab.com`, also see the [disclosure section on the GitLab.com website](https://about.gitlab.com/security/disclosure/). -DANGER: **Warning:** +WARNING: Do **NOT** create publicly viewable issues for suspected security vulnerabilities. ## Code of conduct diff --git a/doc/development/documentation/site_architecture/release_process.md b/doc/development/documentation/site_architecture/release_process.md index 65cd77aace3..e8ec0f39702 100644 --- a/doc/development/documentation/site_architecture/release_process.md +++ b/doc/development/documentation/site_architecture/release_process.md @@ -163,7 +163,7 @@ Releasing a new version is a long process that involves many moving parts. ### `test_internal_links_and_anchors` failing on dropdown merge requests -DANGER: **Deprecated:** +WARNING: We now pin versions in the `.gitlab-ci.yml` of the respective branch, so the steps below are deprecated. diff --git a/doc/development/fe_guide/icons.md b/doc/development/fe_guide/icons.md index 53c84a570be..9c68f4c88f9 100644 --- a/doc/development/fe_guide/icons.md +++ b/doc/development/fe_guide/icons.md @@ -92,7 +92,7 @@ Please use the following function inside JS to render an icon: ### Usage in HAML/Rails -DANGER: **Warning:** +WARNING: Do not use the `spinner` or `icon('spinner spin')` rails helpers to insert loading icons. These helpers rely on the Font Awesome icon library which is deprecated. diff --git a/doc/development/feature_flags/development.md b/doc/development/feature_flags/development.md index 6ddd4417169..9ddc6eb29df 100644 --- a/doc/development/feature_flags/development.md +++ b/doc/development/feature_flags/development.md @@ -193,7 +193,7 @@ if Feature.disabled?(:my_feature_flag, project, type: :ops) end ``` -DANGER: **Warning:** +WARNING: Don't use feature flags at application load time. For example, using the `Feature` class in `config/initializers/*` or at the class level could cause an unexpected error. This error occurs because a database that a feature flag adapter might depend on doesn't exist at load time diff --git a/doc/development/git_object_deduplication.md b/doc/development/git_object_deduplication.md index c642e54c6aa..11ffcd70968 100644 --- a/doc/development/git_object_deduplication.md +++ b/doc/development/git_object_deduplication.md @@ -33,7 +33,7 @@ configuration. Objects in A that are not in B remain in A. For this to work, it is of course critical that **no objects ever get deleted from B** because A might need them. -DANGER: **Warning:** +WARNING: Do not run `git prune` or `git gc` in pool repositories! This can cause data loss in "real" repositories that depend on the pool in question. diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md index 6c6ae20f8d4..d237fa940e3 100644 --- a/doc/gitlab-basics/command-line-commands.md +++ b/doc/gitlab-basics/command-line-commands.md @@ -59,14 +59,14 @@ nano README.md It's easy to delete (remove) a file or directory, but be careful: -DANGER: **Warning:** +WARNING: This will **permanently** delete a file. ```shell rm NAME-OF-FILE ``` -DANGER: **Warning:** +WARNING: This will **permanently** delete a directory and **all** of its contents. ```shell diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md index 77590443eca..5e90b102276 100644 --- a/doc/install/aws/index.md +++ b/doc/install/aws/index.md @@ -312,7 +312,7 @@ We need a security group for our database that will allow inbound traffic from t ### Create the database -DANGER: **Warning:** +WARNING: Avoid using burstable instances (t class instances) for the database as this could lead to performance issues due to CPU credits running out during sustained periods of high load. Now, it's time to create the database: @@ -349,7 +349,7 @@ Now that the database is created, let's move on to setting up Redis with ElastiC ElastiCache is an in-memory hosted caching solution. Redis maintains its own persistence and is used to store session data, temporary cache information, and background job queues for the GitLab application. -DANGER: **Warning:** +WARNING: GitLab recommends you use ElastiCache Redis version 5.0.x, because version 6.x contains a bug that [prevents Sidekiq from processing jobs](https://gitlab.com/gitlab-org/gitlab/-/issues/281683). diff --git a/doc/install/google_cloud_platform/index.md b/doc/install/google_cloud_platform/index.md index f1ac1b0cb95..c895cd26e0b 100644 --- a/doc/install/google_cloud_platform/index.md +++ b/doc/install/google_cloud_platform/index.md @@ -10,7 +10,7 @@ type: howto This guide will help you install GitLab on a [Google Cloud Platform (GCP)](https://cloud.google.com/) instance. -NOTE: **Alternative installation method:** +NOTE: Google provides a whitepaper for [deploying production-ready GitLab on Google Kubernetes Engine](https://cloud.google.com/solutions/deploying-production-ready-gitlab-on-gke), including all steps and external resource configuration. These are an alternative to using a GCP VM, and use diff --git a/doc/integration/kerberos.md b/doc/integration/kerberos.md index 3ac1d2b7f2d..5ccb1552b39 100644 --- a/doc/integration/kerberos.md +++ b/doc/integration/kerberos.md @@ -216,7 +216,7 @@ GitLab users with a linked Kerberos account can also `git pull` and `git push` using Kerberos tokens, i.e., without having to send their password with each operation. -DANGER: **Warning:** +WARNING: There is a [known issue](https://github.com/curl/curl/issues/1261) with `libcurl` older than version 7.64.1 wherein it won't reuse connections when negotiating. This leads to authorization issues when push is larger than `http.postBuffer` diff --git a/doc/operations/incident_management/alert_integrations.md b/doc/operations/incident_management/alert_integrations.md index e380df94ea1..b4597110935 100644 --- a/doc/operations/incident_management/alert_integrations.md +++ b/doc/operations/incident_management/alert_integrations.md @@ -170,7 +170,7 @@ If the existing alert is already `resolved`, GitLab creates a new alert instead. ## Link to your Opsgenie Alerts -DANGER: **Deprecated:** +WARNING: We are building deeper integration with Opsgenie and other alerting tools through [HTTP endpoint integrations](#generic-http-endpoint) so you can see alerts within the GitLab interface. As a result, the previous direct link to Opsgenie Alerts from diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md index e03d1cd6411..0c184aa0075 100644 --- a/doc/raketasks/cleanup.md +++ b/doc/raketasks/cleanup.md @@ -12,7 +12,7 @@ GitLab provides Rake tasks for cleaning up GitLab instances. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36628) in GitLab 12.10. -DANGER: **Warning:** +WARNING: Do not run this within 12 hours of a GitLab upgrade. This is to ensure that all background migrations have finished, which otherwise may lead to data loss. diff --git a/doc/topics/autodevops/customize.md b/doc/topics/autodevops/customize.md index ed863edfe7c..be7f9071dde 100644 --- a/doc/topics/autodevops/customize.md +++ b/doc/topics/autodevops/customize.md @@ -243,7 +243,7 @@ include: See the [Auto DevOps template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml) for information on available jobs. -DANGER: **Deprecated:** +WARNING: Auto DevOps templates using the [`only`](../../ci/yaml/README.md#onlyexcept-basic) or [`except`](../../ci/yaml/README.md#onlyexcept-basic) syntax have switched to the [`rules`](../../ci/yaml/README.md#rules) syntax, starting in diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index 6cadf68d10b..11b8bcdc2f0 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -410,7 +410,7 @@ If you receive this error, you can do one of the following actions: database by setting `AUTO_DEVOPS_POSTGRES_DELETE_V1` to a non-empty value and redeploying. - DANGER: **Warning:** + WARNING: Deleting the channel 1 PostgreSQL database permanently deletes the existing channel 1 database and all its data. See [Upgrading PostgreSQL](upgrading_postgresql.md) @@ -424,7 +424,7 @@ If you receive this error, you can do one of the following actions: and persisted by Helm, regardless of whether or not your chart uses the variable. -DANGER: **Warning:** +WARNING: Setting `POSTGRES_ENABLED` to `false` permanently deletes any existing channel 1 database for your environment. diff --git a/doc/topics/autodevops/stages.md b/doc/topics/autodevops/stages.md index 6825fd6785a..2f84b00af61 100644 --- a/doc/topics/autodevops/stages.md +++ b/doc/topics/autodevops/stages.md @@ -288,7 +288,7 @@ see the documentation. To use a custom target instead of the auto-deployed review apps, set a `DAST_WEBSITE` environment variable to the URL for DAST to scan. -DANGER: **Warning:** +WARNING: If [DAST Full Scan](../../user/application_security/dast/index.md#full-scan) is enabled, GitLab strongly advises **not** to set `DAST_WEBSITE` to any staging or production environment. DAST Full Scan @@ -431,7 +431,7 @@ To use Auto Deploy on a Kubernetes 1.16+ cluster: 1. If you are deploying your application for the first time and are using GitLab 12.9 or 12.10, set `AUTO_DEVOPS_POSTGRES_CHANNEL` to `2`. -DANGER: **Warning:** +WARNING: On GitLab 12.9 and 12.10, opting into `AUTO_DEVOPS_POSTGRES_CHANNEL` version `2` deletes the version `1` PostgreSQL database. Follow the [guide to upgrading PostgreSQL](upgrading_postgresql.md) diff --git a/doc/topics/git/lfs/migrate_from_git_annex_to_git_lfs.md b/doc/topics/git/lfs/migrate_from_git_annex_to_git_lfs.md index 16a14fdbd97..224dcc797d5 100644 --- a/doc/topics/git/lfs/migrate_from_git_annex_to_git_lfs.md +++ b/doc/topics/git/lfs/migrate_from_git_annex_to_git_lfs.md @@ -7,7 +7,7 @@ type: reference, howto # Migration guide from Git Annex to Git LFS -DANGER: **Deprecated:** +WARNING: Git Annex support [has been removed](https://gitlab.com/gitlab-org/gitlab/-/issues/1648) in GitLab Enterprise Edition 9.0 (2017/03/22). diff --git a/doc/user/admin_area/monitoring/health_check.md b/doc/user/admin_area/monitoring/health_check.md index 0df651a5038..01a172fc0d1 100644 --- a/doc/user/admin_area/monitoring/health_check.md +++ b/doc/user/admin_area/monitoring/health_check.md @@ -105,7 +105,7 @@ This check is being exempt from Rack Attack. ## Liveness -DANGER: **Warning:** +WARNING: In GitLab [12.4](https://about.gitlab.com/upcoming-releases/) the response body of the Liveness check was changed to match the example below. diff --git a/doc/user/application_security/api_fuzzing/index.md b/doc/user/application_security/api_fuzzing/index.md index 3789a8c1e19..9113b3d204d 100644 --- a/doc/user/application_security/api_fuzzing/index.md +++ b/doc/user/application_security/api_fuzzing/index.md @@ -139,7 +139,7 @@ This is a minimal configuration for API Fuzzing. From here you can: - [Add authentication](#authentication). - Learn how to [handle false positives](#handling-false-positives). -DANGER: **Warning:** +WARNING: **NEVER** run fuzz testing against a production server. Not only can it perform *any* function that the API can, it may also trigger bugs in the API. This includes actions like modifying and deleting data. Only run fuzzing against a test server. @@ -158,7 +158,7 @@ You can use various tools to generate HAR files: - [Chrome](https://www.google.com/chrome/): Browser - [Firefox](https://www.mozilla.org/en-US/firefox/): Browser -DANGER: **Warning:** +WARNING: HAR files may contain sensitive information such as authentication tokens, API keys, and session cookies. We recommend that you review the HAR file contents before adding them to a repository. @@ -230,7 +230,7 @@ This is a minimal configuration for API Fuzzing. From here you can: - [Add authentication](#authentication). - Learn how to [handle false positives](#handling-false-positives). -DANGER: **Warning:** +WARNING: **NEVER** run fuzz testing against a production server. Not only can it perform *any* function that the API can, it may also trigger bugs in the API. This includes actions like modifying and deleting data. Only run fuzzing against a test server. @@ -247,7 +247,7 @@ When used with GitLab's API fuzzer, Postman Collections must contain definitions test with valid data. The API fuzzer extracts all the API definitions and uses them to perform testing. -DANGER: **Warning:** +WARNING: Postman Collection files may contain sensitive information such as authentication tokens, API keys, and session cookies. We recommend that you review the Postman Collection file contents before adding them to a repository. @@ -321,7 +321,7 @@ This is a minimal configuration for API Fuzzing. From here you can: - [Add authentication](#authentication). - Learn how to [handle false positives](#handling-false-positives). -DANGER: **Warning:** +WARNING: **NEVER** run fuzz testing against a production server. Not only can it perform *any* function that the API can, it may also trigger bugs in the API. This includes actions like modifying and deleting data. Only run fuzzing against a test server. diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md index 48a7c0a5f2b..f4401fa6445 100644 --- a/doc/user/application_security/dast/index.md +++ b/doc/user/application_security/dast/index.md @@ -204,7 +204,7 @@ The results are saved as a that you can later download and analyze. Due to implementation limitations, we always take the latest DAST artifact available. -DANGER: **Warning:** +WARNING: **NEVER** run an authenticated scan against a production server. When an authenticated scan is run, it may perform *any* function that the authenticated user can. This includes actions like modifying and deleting data, submitting forms, and following links. diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md index 160c245b775..19be55c0d77 100644 --- a/doc/user/application_security/secret_detection/index.md +++ b/doc/user/application_security/secret_detection/index.md @@ -40,19 +40,26 @@ The [default ruleset provided by Gitleaks](https://gitlab.com/gitlab-org/securit - Cloud services: - Amazon Web Services (AWS) - Google Cloud Platform (GCP) -Encryption keys: + - Heroku API +- Encryption keys: - PKCS8 - RSA - SSH - PGP + - DSA + - EC - Social media platforms: - Facebook API - Twitter API - Cloud SaaS vendors: - GitHub API - Slack Token + - Slack Webhook - Stripe API + - Twilio API - Generic API key strings starting with `api-` +- Password in URL +- U.S. Social Security Number ## Requirements @@ -252,6 +259,27 @@ We have created a [short video walkthrough](https://youtu.be/wDtc_K00Y0A) showca +## Running Secret Detection in an offline environment + +For self-managed GitLab instances in an environment with limited, restricted, or intermittent access +to external resources through the internet, some adjustments are required for the Secret Detection job to +run successfully. For more information, see [Offline environments](../offline_deployments/index.md). + +### Requirements for offline Secret Detection + +To use Secret Detection in an offline environment, you need: + +- GitLab Runner with the [`docker` or `kubernetes` executor](#requirements). +- A Docker Container Registry with locally available copy of Secret Detection [analyzer](https://gitlab.com/gitlab-org/security-products/analyzers) images. +- Configure certificate checking of packages (optional). + +GitLab Runner has a [default `pull policy` of `always`](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy), +meaning the runner tries to pull Docker images from the GitLab container registry even if a local +copy is available. The GitLab Runner [`pull_policy` can be set to `if-not-present`](https://docs.gitlab.com/runner/executors/docker.html#using-the-if-not-present-pull-policy) +in an offline environment if you prefer using only locally available Docker images. However, we +recommend keeping the pull policy setting to `always` if not in an offline environment, as this +enables the use of updated scanners in your CI/CD pipelines. + ### Make GitLab Secret Detection analyzer image available inside your Docker registry Import the following default Secret Detection analyzer images from `registry.gitlab.com` into your @@ -278,6 +306,22 @@ Support for custom certificate authorities was introduced in the following versi | -------- | ------- | | secrets | [v3.0.0](https://gitlab.com/gitlab-org/security-products/analyzers/secrets/-/releases/v3.0.0) | +### Set Secret Detection CI job variables to use local Secret Detection analyzer + +Add the following configuration to your `.gitlab-ci.yml` file. You must replace +`SECURE_ANALYZERS_PREFIX` to refer to your local Docker container registry: + +```yaml +include: + - template: Security/Secret-Detection.gitlab-ci.yml + +variables: + SECURE_ANALYZERS_PREFIX: "localhost:5000/analyzers" +``` + +The Secret Detection job should now use local copies of the Secret Detection analyzer to scan your code and generate +security reports without requiring internet access. + ## Troubleshooting ### Getting warning message `gl-secret-detection-report.json: no matching files` diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md index f1895e11571..e347221bd66 100644 --- a/doc/user/profile/account/delete_account.md +++ b/doc/user/profile/account/delete_account.md @@ -35,7 +35,7 @@ As an administrator, you can delete a user account by: - **Delete user and contributions** to delete the user and their associated records. -DANGER: **Warning:** +WARNING: Using the **Delete user and contributions** option may result in removing more data than intended. Please see [associated records](#associated-records) below for additional details. diff --git a/doc/user/profile/active_sessions.md b/doc/user/profile/active_sessions.md index 4716740ba3d..381015f17c3 100644 --- a/doc/user/profile/active_sessions.md +++ b/doc/user/profile/active_sessions.md @@ -32,7 +32,7 @@ exceeds 100, the oldest ones are deleted. 1. Use the previous steps to navigate to **Active Sessions**. 1. Click on **Revoke** besides a session. The current session cannot be revoked, as this would sign you out of GitLab. -NOTE: **Note:** +NOTE: When any session is revoked all **Remember me** tokens for all devices are revoked. See ['Why do I keep getting signed out?'](index.md#why-do-i-keep-getting-signed-out) for more information about the **Remember me** feature. diff --git a/doc/user/project/deploy_boards.md b/doc/user/project/deploy_boards.md index dd7b2bf99d2..90bad9529d8 100644 --- a/doc/user/project/deploy_boards.md +++ b/doc/user/project/deploy_boards.md @@ -74,7 +74,7 @@ To display the Deploy Boards for a specific [environment](../../ci/environments/ 1. Have a Kubernetes cluster up and running. - NOTE: **Running on OpenShift:** + NOTE: If you are using OpenShift, ensure that you're using the `Deployment` resource instead of `DeploymentConfiguration`. Otherwise, the Deploy Boards won't render correctly. For more information, read the diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md index 45289d615a8..5b82a411401 100644 --- a/doc/user/project/quick_actions.md +++ b/doc/user/project/quick_actions.md @@ -34,7 +34,7 @@ The following quick actions are applicable to descriptions, discussions and thre | `/award :emoji:` | ✓ | ✓ | ✓ | Toggle emoji award. | | `/child_epic ` | | | ✓ | Add child epic to ``. The `` value should be in the format of `&epic`, `group&epic`, or a URL to an epic ([introduced in GitLab 12.0](https://gitlab.com/gitlab-org/gitlab/-/issues/7330)). **(ULTIMATE)** | | `/clear_weight` | ✓ | | | Clear weight. **(STARTER)** | -| `/clone ` | ✓ | | | Clone the issue to given project, or the current one if no arguments are given ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9421) in GitLab 13.7). Copies as much data as possible as long as the target project contains equivalent labels, milestones, etc. Does not copy comments or system notes. | +| `/clone [--with_notes]`| ✓ | | | Clone the issue to given project, or the current one if no arguments are given ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9421) in GitLab 13.7). Copies as much data as possible as long as the target project contains equivalent labels, milestones, and so on. Does not copy comments or system notes unless `--with_notes` is provided as an argument. | | `/close` | ✓ | ✓ | ✓ | Close. | | `/confidential` | ✓ | | | Make confidential. | | `/copy_metadata ` | ✓ | ✓ | | Copy labels and milestone from another merge request in the project. | diff --git a/doc/user/project/repository/reducing_the_repo_size_using_git.md b/doc/user/project/repository/reducing_the_repo_size_using_git.md index c743d7a2fa9..3dfb0ddec95 100644 --- a/doc/user/project/repository/reducing_the_repo_size_using_git.md +++ b/doc/user/project/repository/reducing_the_repo_size_using_git.md @@ -18,7 +18,7 @@ We **recommend [`git filter-repo`](https://github.com/newren/git-filter-repo/blo over [`git filter-branch`](https://git-scm.com/docs/git-filter-branch) and [BFG](https://rtyley.github.io/bfg-repo-cleaner/). -DANGER: **Warning:** +WARNING: Rewriting repository history is a destructive operation. Make sure to back up your repository before you begin. The best way back up a repository is to [export the project](../settings/import_export.md#exporting-a-project-and-its-data). diff --git a/doc/user/project/service_desk.md b/doc/user/project/service_desk.md index d3156d860c8..3b9a2319ca5 100644 --- a/doc/user/project/service_desk.md +++ b/doc/user/project/service_desk.md @@ -76,7 +76,7 @@ Follow these steps to do so: address's format. The older format is still supported, however, allowing existing aliases or contacts to continue working. - DANGER: **Warning:** + WARNING: This email address can be used by anyone to create an issue on this project, whether or not they have access to your GitLab instance. We recommend **putting this behind an alias** so it can be changed if needed, and **[enabling Akismet](../../integration/akismet.md)** on your GitLab diff --git a/doc/user/search/advanced_global_search.md b/doc/user/search/advanced_global_search.md index ccc083e94f4..3a52cb3671f 100644 --- a/doc/user/search/advanced_global_search.md +++ b/doc/user/search/advanced_global_search.md @@ -9,7 +9,7 @@ type: reference > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109) in GitLab [Starter](https://about.gitlab.com/pricing/) 8.4. -NOTE: **GitLab.com availability:** +NOTE: Advanced Search (powered by Elasticsearch) is enabled for Bronze and above on GitLab.com since 2020-07-10. Leverage Elasticsearch for faster, more advanced code search across your entire diff --git a/doc/user/search/advanced_search_syntax.md b/doc/user/search/advanced_search_syntax.md index 6786b1053ae..afca2c349fa 100644 --- a/doc/user/search/advanced_search_syntax.md +++ b/doc/user/search/advanced_search_syntax.md @@ -9,7 +9,7 @@ type: reference > - Introduced in [GitLab Enterprise Starter](https://about.gitlab.com/pricing/) 9.2 -NOTE: **GitLab.com availability:** +NOTE: Advanced Search (powered by Elasticsearch) is enabled for Bronze and above on GitLab.com since 2020-07-10. Use advanced queries for more targeted search results. diff --git a/lib/api/helpers/packages/conan/api_helpers.rb b/lib/api/helpers/packages/conan/api_helpers.rb index 0e34a5c9a76..39ecfc171a9 100644 --- a/lib/api/helpers/packages/conan/api_helpers.rb +++ b/lib/api/helpers/packages/conan/api_helpers.rb @@ -222,6 +222,7 @@ module API return unless route_authentication_setting[:job_token_allowed] job = find_job_from_token || raise(::Gitlab::Auth::UnauthorizedError) + @current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables job.user end diff --git a/lib/gitlab/quick_actions/issue_actions.rb b/lib/gitlab/quick_actions/issue_actions.rb index 400547bb6c1..1822b0c8bd5 100644 --- a/lib/gitlab/quick_actions/issue_actions.rb +++ b/lib/gitlab/quick_actions/issue_actions.rb @@ -106,17 +106,28 @@ module Gitlab explanation do |project = quick_action_target.project.full_path| _("Clones this issue, without comments, to %{project}.") % { project: project } end - params 'path/to/project' + params 'path/to/project [--with_notes]' types Issue condition do quick_action_target.persisted? && current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project) end - command :clone do |target_project_path = nil| + command :clone do |params = ''| + params = params.split(' ') + with_notes = params.delete('--with_notes').present? + + # If we have more than 1 param, then the user supplied too many spaces, or mistyped `--with_notes` + if params.size > 1 + @execution_message[:clone] = _('Failed to clone this issue: wrong parameters.') + next + end + + target_project_path = params[0] target_project = target_project_path.present? ? Project.find_by_full_path(target_project_path) : quick_action_target.project if target_project.present? @updates[:target_clone_project] = target_project + @updates[:clone_with_notes] = with_notes message = _("Cloned this issue to %{path_to_project}.") % { path_to_project: target_project_path || quick_action_target.project.full_path } else diff --git a/lib/gitlab/usage_data_counters/counter_events/guest_package_events.yml b/lib/gitlab/usage_data_counters/counter_events/guest_package_events.yml new file mode 100644 index 00000000000..a9b9f8ea235 --- /dev/null +++ b/lib/gitlab/usage_data_counters/counter_events/guest_package_events.yml @@ -0,0 +1,34 @@ +--- +- i_package_composer_guest_delete +- i_package_composer_guest_pull +- i_package_composer_guest_push +- i_package_conan_guest_delete +- i_package_conan_guest_pull +- i_package_conan_guest_push +- i_package_container_guest_delete +- i_package_container_guest_pull +- i_package_container_guest_push +- i_package_debian_guest_delete +- i_package_debian_guest_pull +- i_package_debian_guest_push +- i_package_generic_guest_delete +- i_package_generic_guest_pull +- i_package_generic_guest_push +- i_package_golang_guest_delete +- i_package_golang_guest_pull +- i_package_golang_guest_push +- i_package_maven_guest_delete +- i_package_maven_guest_pull +- i_package_maven_guest_push +- i_package_npm_guest_delete +- i_package_npm_guest_pull +- i_package_npm_guest_push +- i_package_nuget_guest_delete +- i_package_nuget_guest_pull +- i_package_nuget_guest_push +- i_package_pypi_guest_delete +- i_package_pypi_guest_pull +- i_package_pypi_guest_push +- i_package_tag_guest_delete +- i_package_tag_guest_pull +- i_package_tag_guest_push diff --git a/lib/gitlab/usage_data_counters/guest_package_event_counter.rb b/lib/gitlab/usage_data_counters/guest_package_event_counter.rb new file mode 100644 index 00000000000..a9bcbfadda2 --- /dev/null +++ b/lib/gitlab/usage_data_counters/guest_package_event_counter.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Gitlab + module UsageDataCounters + class GuestPackageEventCounter < BaseCounter + KNOWN_EVENTS_PATH = File.expand_path('counter_events/guest_package_events.yml', __dir__) + KNOWN_EVENTS = YAML.safe_load(File.read(KNOWN_EVENTS_PATH)).freeze + PREFIX = 'package_guest' + end + end +end diff --git a/lib/tasks/gitlab/packages/events.rake b/lib/tasks/gitlab/packages/events.rake index 14d47c02e31..ca507fb5320 100644 --- a/lib/tasks/gitlab/packages/events.rake +++ b/lib/tasks/gitlab/packages/events.rake @@ -5,11 +5,29 @@ namespace :gitlab do namespace :packages do namespace :events do task generate: :environment do + Rake::Task["gitlab:packages:events:generate_guest"].invoke + Rake::Task["gitlab:packages:events:generate_unique"].invoke + rescue => e + logger.error("Error building events list: #{e}") + end + + task generate_guest: :environment do logger = Logger.new(STDOUT) logger.info('Building list of package events...') - path = File.join(File.dirname(::Gitlab::UsageDataCounters::HLLRedisCounter::KNOWN_EVENTS_PATH), 'package_events.yml') + path = Gitlab::UsageDataCounters::GuestPackageEventCounter::KNOWN_EVENTS_PATH + File.open(path, "w") { |file| file << guest_events_list.to_yaml } + logger.info("Events file `#{path}` generated successfully") + rescue => e + logger.error("Error building events list: #{e}") + end + + task generate_unique: :environment do + logger = Logger.new(STDOUT) + logger.info('Building list of package events...') + + path = File.join(File.dirname(Gitlab::UsageDataCounters::HLLRedisCounter::KNOWN_EVENTS_PATH), 'package_events.yml') File.open(path, "w") { |file| file << generate_unique_events_list.to_yaml } logger.info("Events file `#{path}` generated successfully") @@ -17,14 +35,16 @@ namespace :gitlab do logger.error("Error building events list: #{e}") end + private + def event_pairs - ::Packages::Event.event_types.keys.product(::Packages::Event::EVENT_SCOPES.keys) + Packages::Event.event_types.keys.product(Packages::Event::EVENT_SCOPES.keys) end def generate_unique_events_list events = event_pairs.each_with_object([]) do |(event_type, event_scope), events| - ::Packages::Event.originator_types.keys.excluding('guest').each do |originator| - if name = ::Packages::Event.allowed_event_name(event_scope, event_type, originator) + Packages::Event.originator_types.keys.excluding('guest').each do |originator| + if name = Packages::Event.allowed_event_name(event_scope, event_type, originator) events << { "name" => name, "category" => "#{event_scope}_packages", @@ -38,6 +58,12 @@ namespace :gitlab do events.sort_by { |event| event["name"] } end + + def guest_events_list + event_pairs.map do |event_type, event_scope| + Packages::Event.allowed_event_name(event_scope, event_type, "guest") + end.compact.sort + end end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index f5113f7f441..53e92f806ee 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -11469,6 +11469,9 @@ msgstr "" msgid "Failed to clone this issue because target project doesn't exist." msgstr "" +msgid "Failed to clone this issue: wrong parameters." +msgstr "" + msgid "Failed to create Merge Request. Please try again." msgstr "" diff --git a/spec/frontend/design_management/pages/design/index_spec.js b/spec/frontend/design_management/pages/design/index_spec.js index 88892bb1878..9c11af28cf0 100644 --- a/spec/frontend/design_management/pages/design/index_spec.js +++ b/spec/frontend/design_management/pages/design/index_spec.js @@ -2,7 +2,9 @@ import { shallowMount, createLocalVue } from '@vue/test-utils'; import VueRouter from 'vue-router'; import { GlAlert } from '@gitlab/ui'; import { ApolloMutation } from 'vue-apollo'; +import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; import createFlash from '~/flash'; +import Api from '~/api'; import DesignIndex from '~/design_management/pages/design/index.vue'; import DesignSidebar from '~/design_management/components/design_sidebar.vue'; import DesignPresentation from '~/design_management/components/design_presentation.vue'; @@ -20,8 +22,14 @@ import design from '../../mock_data/design'; import mockResponseWithDesigns from '../../mock_data/designs'; import mockResponseNoDesigns from '../../mock_data/no_designs'; import mockAllVersions from '../../mock_data/all_versions'; +import { + DESIGN_TRACKING_PAGE_NAME, + DESIGN_SNOWPLOW_EVENT_TYPES, + DESIGN_USAGE_PING_EVENT_TYPES, +} from '~/design_management/utils/tracking'; jest.mock('~/flash'); +jest.mock('~/api.js'); const focusInput = jest.fn(); const mutate = jest.fn().mockResolvedValue(); @@ -81,7 +89,10 @@ describe('Design management design index page', () => { const findSidebar = () => wrapper.find(DesignSidebar); const findDesignPresentation = () => wrapper.find(DesignPresentation); - function createComponent({ loading = false } = {}, { data = {}, intialRouteOptions = {} } = {}) { + function createComponent( + { loading = false } = {}, + { data = {}, intialRouteOptions = {}, provide = {} } = {}, + ) { const $apollo = { queries: { design: { @@ -106,6 +117,7 @@ describe('Design management design index page', () => { provide: { issueIid: '1', projectPath: 'project-path', + ...provide, }, data() { return { @@ -343,4 +355,64 @@ describe('Design management design index page', () => { }); }); }); + + describe('tracking', () => { + let trackingSpy; + + beforeEach(() => { + trackingSpy = mockTracking('_category_', undefined, jest.spyOn); + }); + + afterEach(() => { + unmockTracking(); + }); + + describe('on mount', () => { + it('tracks design view in snowplow', () => { + createComponent({ loading: true }); + + expect(trackingSpy).toHaveBeenCalledTimes(1); + expect(trackingSpy).toHaveBeenCalledWith( + DESIGN_TRACKING_PAGE_NAME, + DESIGN_SNOWPLOW_EVENT_TYPES.VIEW_DESIGN, + { + context: { + data: { + 'design-collection-owner': 'issue', + 'design-is-current-version': true, + 'design-version-number': 1, + 'internal-object-referrer': 'issue-design-collection', + }, + schema: 'iglu:com.gitlab/design_management_context/jsonschema/1-0-0', + }, + label: DESIGN_SNOWPLOW_EVENT_TYPES.VIEW_DESIGN, + }, + ); + }); + + describe('with usage_data_design_action enabled', () => { + it('tracks design view usage ping', () => { + createComponent( + { loading: true }, + { + provide: { + glFeatures: { usageDataDesignAction: true }, + }, + }, + ); + expect(Api.trackRedisHllUserEvent).toHaveBeenCalledTimes(1); + expect(Api.trackRedisHllUserEvent).toHaveBeenCalledWith( + DESIGN_USAGE_PING_EVENT_TYPES.DESIGN_ACTION, + ); + }); + }); + + describe('with usage_data_design_action disabled', () => { + it("doesn't track design view usage ping", () => { + createComponent({ loading: true }); + expect(Api.trackRedisHllUserEvent).toHaveBeenCalledTimes(0); + }); + }); + }); + }); }); diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js index 05238efd761..147169dd9aa 100644 --- a/spec/frontend/design_management/pages/index_spec.js +++ b/spec/frontend/design_management/pages/index_spec.js @@ -31,7 +31,10 @@ import { moveDesignMutationResponseWithErrors, } from '../mock_data/apollo_mock'; import moveDesignMutation from '~/design_management/graphql/mutations/move_design.mutation.graphql'; -import { DESIGN_TRACKING_PAGE_NAME } from '~/design_management/utils/tracking'; +import { + DESIGN_TRACKING_PAGE_NAME, + DESIGN_SNOWPLOW_EVENT_TYPES, +} from '~/design_management/utils/tracking'; jest.mock('~/flash.js'); const mockPageEl = { @@ -509,14 +512,20 @@ describe('Design management index page', () => { wrapper.vm.onUploadDesignDone(designUploadMutationCreatedResponse); expect(trackingSpy).toHaveBeenCalledTimes(1); - expect(trackingSpy).toHaveBeenCalledWith(DESIGN_TRACKING_PAGE_NAME, 'create_design'); + expect(trackingSpy).toHaveBeenCalledWith( + DESIGN_TRACKING_PAGE_NAME, + DESIGN_SNOWPLOW_EVENT_TYPES.CREATE_DESIGN, + ); }); it('tracks design modification', () => { wrapper.vm.onUploadDesignDone(designUploadMutationUpdatedResponse); expect(trackingSpy).toHaveBeenCalledTimes(1); - expect(trackingSpy).toHaveBeenCalledWith(DESIGN_TRACKING_PAGE_NAME, 'update_design'); + expect(trackingSpy).toHaveBeenCalledWith( + DESIGN_TRACKING_PAGE_NAME, + DESIGN_SNOWPLOW_EVENT_TYPES.UPDATE_DESIGN, + ); }); }); }); diff --git a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js index 2544d0bd030..2c02e1e1de4 100644 --- a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js +++ b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js @@ -280,7 +280,7 @@ describe('RelatedIssuesRoot', () => { const input = 'asdf/qwer#444 #12 '; wrapper.vm.onInput({ untouchedRawReferences: input.trim().split(/\s/), - touchedReference: 2, + touchedReference: '2', }); expect(wrapper.vm.state.pendingReferences).toHaveLength(2); @@ -292,13 +292,37 @@ describe('RelatedIssuesRoot', () => { const input = 'something random '; wrapper.vm.onInput({ untouchedRawReferences: input.trim().split(/\s/), - touchedReference: 2, + touchedReference: '2', }); expect(wrapper.vm.state.pendingReferences).toHaveLength(2); expect(wrapper.vm.state.pendingReferences[0]).toEqual('something'); expect(wrapper.vm.state.pendingReferences[1]).toEqual('random'); }); + + it('prepends # when user enters a numeric value [0-9]', async () => { + const input = '23'; + + wrapper.vm.onInput({ + untouchedRawReferences: input.trim().split(/\s/), + touchedReference: input, + }); + + expect(wrapper.vm.inputValue).toBe(`#${input}`); + }); + + it('prepends # when user enters a number', async () => { + const input = 23; + + wrapper.vm.onInput({ + untouchedRawReferences: String(input) + .trim() + .split(/\s/), + touchedReference: input, + }); + + expect(wrapper.vm.inputValue).toBe(`#${input}`); + }); }); describe('onBlur', () => { diff --git a/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb b/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb new file mode 100644 index 00000000000..c0367f7d42e --- /dev/null +++ b/spec/graphql/resolvers/project_pipeline_statistics_resolver_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Resolvers::ProjectPipelineStatisticsResolver do + include GraphqlHelpers + + let_it_be(:project) { create(:project) } + + specify do + expect(described_class).to have_nullable_graphql_type(::Types::Ci::AnalyticsType) + end + + def resolve_statistics(project, args) + resolve(described_class, obj: project, args: args) + end + + describe '#resolve' do + it 'returns the pipelines statistics for a given project' do + result = resolve_statistics(project, {}) + expect(result.keys).to contain_exactly( + :week_pipelines_labels, + :week_pipelines_totals, + :week_pipelines_successful, + :month_pipelines_labels, + :month_pipelines_totals, + :month_pipelines_successful, + :year_pipelines_labels, + :year_pipelines_totals, + :year_pipelines_successful, + :pipeline_times_labels, + :pipeline_times_values + ) + end + end +end diff --git a/spec/graphql/types/ci/analytics_type_spec.rb b/spec/graphql/types/ci/analytics_type_spec.rb new file mode 100644 index 00000000000..c8462d40769 --- /dev/null +++ b/spec/graphql/types/ci/analytics_type_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::Ci::AnalyticsType do + it 'exposes the expected fields' do + expected_fields = %i[ + weekPipelinesTotals + weekPipelinesLabels + weekPipelinesSuccessful + monthPipelinesLabels + monthPipelinesTotals + monthPipelinesSuccessful + yearPipelinesLabels + yearPipelinesTotals + yearPipelinesSuccessful + pipelineTimesLabels + pipelineTimesValues + ] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index 141f2406e7f..ff99dd77233 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -31,6 +31,7 @@ RSpec.describe GitlabSchema.types['Project'] do container_expiration_policy service_desk_enabled service_desk_address issue_status_counts terraform_states alert_management_integrations container_repositories container_repositories_count + pipeline_analytics total_pipeline_duration ] expect(described_class).to include_graphql_fields(*expected_fields) @@ -186,4 +187,11 @@ RSpec.describe GitlabSchema.types['Project'] do end end end + + describe 'pipeline_analytics field' do + subject { described_class.fields['pipelineAnalytics'] } + + it { is_expected.to have_graphql_type(Types::Ci::AnalyticsType) } + it { is_expected.to have_graphql_resolver(Resolvers::ProjectPipelineStatisticsResolver) } + end end diff --git a/spec/lib/gitlab/usage_data_counters/guest_package_event_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/guest_package_event_counter_spec.rb new file mode 100644 index 00000000000..d018100b041 --- /dev/null +++ b/spec/lib/gitlab/usage_data_counters/guest_package_event_counter_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::UsageDataCounters::GuestPackageEventCounter, :clean_gitlab_redis_shared_state do + shared_examples_for 'usage counter with totals' do |counter| + it 'increments counter and returns total count' do + expect(described_class.read(counter)).to eq(0) + + 2.times { described_class.count(counter) } + + expect(described_class.read(counter)).to eq(2) + end + end + + it 'includes the right events' do + expect(described_class::KNOWN_EVENTS.size).to eq 33 + end + + described_class::KNOWN_EVENTS.each do |event| + it_behaves_like 'usage counter with totals', event + end + + describe '.fetch_supported_event' do + subject { described_class.fetch_supported_event(event_name) } + + let(:event_name) { 'package_guest_i_package_composer_guest_push' } + + it { is_expected.to eq 'i_package_composer_guest_push' } + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 3bcb21bc828..a00cc019f59 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -4981,6 +4981,7 @@ RSpec.describe Project, factory_default: :keep do expect(project).to receive(:after_create_default_branch) expect(project).to receive(:refresh_markdown_cache!) expect(InternalId).to receive(:flush_records!).with(project: project) + expect(ProjectCacheWorker).to receive(:perform_async).with(project.id, [], [:repository_size]) expect(DetectRepositoryLanguagesWorker).to receive(:perform_async).with(project.id) expect(project).to receive(:write_repository_config) diff --git a/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb b/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb new file mode 100644 index 00000000000..0f495f3e671 --- /dev/null +++ b/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'rendering project pipeline statistics' do + include GraphqlHelpers + + let_it_be(:project) { create(:project) } + let(:user) { create(:user) } + + let(:fields) do + <<~QUERY + weekPipelinesTotals + weekPipelinesLabels + monthPipelinesLabels + monthPipelinesTotals + yearPipelinesLabels + yearPipelinesTotals + QUERY + end + + let(:query) do + graphql_query_for('project', + { 'fullPath' => project.full_path }, + query_graphql_field('pipelineAnalytics', {}, fields)) + end + + before do + project.add_maintainer(user) + end + + it_behaves_like 'a working graphql query' do + before do + post_graphql(query, current_user: user) + end + end + + it "contains two arrays of 8 elements each for the week pipelines" do + post_graphql(query, current_user: user) + + expect(graphql_data_at(:project, :pipelineAnalytics, :weekPipelinesTotals).length).to eq(8) + expect(graphql_data_at(:project, :pipelineAnalytics, :weekPipelinesLabels).length).to eq(8) + end + + it "contains two arrays of 31 elements each for the month pipelines" do + post_graphql(query, current_user: user) + + expect(graphql_data_at(:project, :pipelineAnalytics, :monthPipelinesTotals).length).to eq(31) + expect(graphql_data_at(:project, :pipelineAnalytics, :monthPipelinesLabels).length).to eq(31) + end + + it "contains two arrays of 13 elements each for the year pipelines" do + post_graphql(query, current_user: user) + + expect(graphql_data_at(:project, :pipelineAnalytics, :yearPipelinesTotals).length).to eq(13) + expect(graphql_data_at(:project, :pipelineAnalytics, :yearPipelinesLabels).length).to eq(13) + end +end diff --git a/spec/requests/import/gitlab_groups_controller_spec.rb b/spec/requests/import/gitlab_groups_controller_spec.rb index fe8875f25f8..51f1363cf1c 100644 --- a/spec/requests/import/gitlab_groups_controller_spec.rb +++ b/spec/requests/import/gitlab_groups_controller_spec.rb @@ -195,6 +195,7 @@ RSpec.describe Import::GitlabGroupsController do describe 'POST authorize' do it_behaves_like 'handle uploads authorize request' do let(:uploader_class) { ImportExportUploader } + let(:maximum_size) { Gitlab::CurrentSettings.max_import_size.megabytes } subject { post authorize_import_gitlab_group_path, headers: workhorse_headers } end diff --git a/spec/requests/import/gitlab_projects_controller_spec.rb b/spec/requests/import/gitlab_projects_controller_spec.rb index 0e92410a2de..d7d4de21a33 100644 --- a/spec/requests/import/gitlab_projects_controller_spec.rb +++ b/spec/requests/import/gitlab_projects_controller_spec.rb @@ -86,6 +86,7 @@ RSpec.describe Import::GitlabProjectsController do describe 'POST authorize' do it_behaves_like 'handle uploads authorize request' do let(:uploader_class) { ImportExportUploader } + let(:maximum_size) { Gitlab::CurrentSettings.max_import_size.megabytes } subject { post authorize_import_gitlab_project_path, headers: workhorse_headers } end diff --git a/spec/services/issues/clone_service_spec.rb b/spec/services/issues/clone_service_spec.rb index d28fc40d32e..12b8781031b 100644 --- a/spec/services/issues/clone_service_spec.rb +++ b/spec/services/issues/clone_service_spec.rb @@ -15,10 +15,12 @@ RSpec.describe Issues::CloneService do let_it_be(:old_project) { create(:project, namespace: sub_group_1) } let_it_be(:new_project) { create(:project, namespace: sub_group_2) } - let(:old_issue) do + let_it_be(:old_issue, reload: true) do create(:issue, title: title, description: description, project: old_project, author: author) end + let(:with_notes) { false } + subject(:clone_service) do described_class.new(old_project, user) end @@ -35,7 +37,7 @@ RSpec.describe Issues::CloneService do include_context 'user can clone issue' context 'generic issue' do - let!(:new_issue) { clone_service.execute(old_issue, new_project) } + let!(:new_issue) { clone_service.execute(old_issue, new_project, with_notes: with_notes) } it 'creates a new issue in the selected project' do expect do @@ -91,6 +93,16 @@ RSpec.describe Issues::CloneService do it 'does not set moved_issue' do expect(old_issue.moved?).to eq(false) end + + context 'when copying comments' do + let(:with_notes) { true } + + it 'does not create extra system notes' do + new_issue = clone_service.execute(old_issue, new_project, with_notes: with_notes) + + expect(new_issue.notes.count).to eq(old_issue.notes.count) + end + end end context 'issue with award emoji' do @@ -200,6 +212,34 @@ RSpec.describe Issues::CloneService do end end + # These tests verify that notes are copied. More thorough tests are in + # the unit test for Notes::CopyService. + context 'issue with notes' do + let_it_be(:notes) do + [ + create(:note, noteable: old_issue, project: old_project, created_at: 2.weeks.ago, updated_at: 1.week.ago), + create(:note, noteable: old_issue, project: old_project) + ] + end + + let(:new_issue) { clone_service.execute(old_issue, new_project, with_notes: with_notes) } + + let(:copied_notes) { new_issue.notes.limit(notes.size) } # Remove the system note added by the copy itself + + it 'does not copy notes' do + # only the system note + expect(copied_notes.order('id ASC').pluck(:note).size).to eq(1) + end + + context 'when copying comments' do + let(:with_notes) { true } + + it 'copies existing notes in order' do + expect(copied_notes.order('id ASC').pluck(:note)).to eq(notes.map(&:note)) + end + end + end + context 'issue with a design', :clean_gitlab_redis_shared_state do let_it_be(:new_project) { create(:project) } let!(:design) { create(:design, :with_lfs_file, issue: old_issue) } diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 5dd60226e3f..55d6d5cfe2d 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -979,15 +979,35 @@ RSpec.describe Issues::UpdateService, :mailer do it 'calls the move service with the proper issue and project' do clone_stub = instance_double(Issues::CloneService) allow(Issues::CloneService).to receive(:new).and_return(clone_stub) - allow(clone_stub).to receive(:execute).with(issue, target_project).and_return(issue) + allow(clone_stub).to receive(:execute).with(issue, target_project, with_notes: nil).and_return(issue) - expect(clone_stub).to receive(:execute).with(issue, target_project) + expect(clone_stub).to receive(:execute).with(issue, target_project, with_notes: nil) update_issue(target_clone_project: target_project) end end end + context 'clone an issue with notes' do + context 'valid project' do + let(:target_project) { create(:project) } + + before do + target_project.add_maintainer(user) + end + + it 'calls the move service with the proper issue and project' do + clone_stub = instance_double(Issues::CloneService) + allow(Issues::CloneService).to receive(:new).and_return(clone_stub) + allow(clone_stub).to receive(:execute).with(issue, target_project, with_notes: true).and_return(issue) + + expect(clone_stub).to receive(:execute).with(issue, target_project, with_notes: true) + + update_issue(target_clone_project: target_project, clone_with_notes: true) + end + end + end + context 'when moving an issue ' do it 'raises an error for invalid move ids within a project' do opts = { move_between_ids: [9000, non_existing_record_id] } diff --git a/spec/support/shared_examples/quick_actions/issue/clone_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/clone_quick_action_shared_examples.rb index 35d65302a61..a99304f7214 100644 --- a/spec/support/shared_examples/quick_actions/issue/clone_quick_action_shared_examples.rb +++ b/spec/support/shared_examples/quick_actions/issue/clone_quick_action_shared_examples.rb @@ -32,6 +32,34 @@ RSpec.shared_examples 'clone quick action' do expect(page).to have_content 'Issues 1' end + + context 'when cloning with notes', :aggregate_failures do + it 'clones the issue with all notes' do + add_note("Some random note") + add_note("Another note") + + add_note("/clone --with_notes #{target_project.full_path}") + + expect(page).to have_content "Cloned this issue to #{target_project.full_path}." + expect(issue.reload).to be_open + + visit project_issue_path(target_project, issue) + + expect(page).to have_content 'Issues 1' + expect(page).to have_content 'Some random note' + expect(page).to have_content 'Another note' + end + + it 'returns an error if the params are malformed' do + # Note that this is missing one `-` + add_note("/clone -with_notes #{target_project.full_path}") + + wait_for_requests + + expect(page).to have_content 'Failed to clone this issue: wrong parameters.' + expect(issue.reload).to be_open + end + end end context 'when the project is valid but the user not authorized' do diff --git a/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb index c56290a0aa9..49b6fc13900 100644 --- a/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb @@ -629,6 +629,7 @@ RSpec.shared_examples 'workhorse recipe file upload endpoint' do it_behaves_like 'rejects invalid recipe' it_behaves_like 'rejects invalid file_name', 'conanfile.py.git%2fgit-upload-pack' it_behaves_like 'uploads a package file' + it_behaves_like 'creates build_info when there is a job' end RSpec.shared_examples 'workhorse package file upload endpoint' do @@ -649,6 +650,7 @@ RSpec.shared_examples 'workhorse package file upload endpoint' do it_behaves_like 'rejects invalid recipe' it_behaves_like 'rejects invalid file_name', 'conaninfo.txttest' it_behaves_like 'uploads a package file' + it_behaves_like 'creates build_info when there is a job' context 'tracking the conan_package.tgz upload' do let(:file_name) { ::Packages::Conan::FileMetadatum::PACKAGE_BINARY } @@ -657,6 +659,20 @@ RSpec.shared_examples 'workhorse package file upload endpoint' do end end +RSpec.shared_examples 'creates build_info when there is a job' do + context 'with job token' do + let(:jwt) { build_jwt_from_job(job) } + + it 'creates a build_info record' do + expect { subject }.to change { Packages::BuildInfo.count }.by(1) + end + + it 'creates a package_file_build_info record' do + expect { subject }.to change { Packages::PackageFileBuildInfo.count }.by(1) + end + end +end + RSpec.shared_examples 'uploads a package file' do context 'file size above maximum limit' do before do diff --git a/spec/support/shared_examples/requests/uploads_auhorize_shared_examples.rb b/spec/support/shared_examples/requests/uploads_auhorize_shared_examples.rb index 3d018fd4028..9cef5cfc25e 100644 --- a/spec/support/shared_examples/requests/uploads_auhorize_shared_examples.rb +++ b/spec/support/shared_examples/requests/uploads_auhorize_shared_examples.rb @@ -37,6 +37,7 @@ RSpec.shared_examples 'handle uploads authorize request' do expect(json_response['RemoteObject']).to have_key('StoreURL') expect(json_response['RemoteObject']).to have_key('DeleteURL') expect(json_response['RemoteObject']).to have_key('MultipartUpload') + expect(json_response['MaximumSize']).to eq(maximum_size) end end @@ -52,6 +53,7 @@ RSpec.shared_examples 'handle uploads authorize request' do expect(response.media_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE) expect(json_response['TempPath']).to eq(uploader_class.workhorse_local_upload_path) expect(json_response['RemoteObject']).to be_nil + expect(json_response['MaximumSize']).to eq(maximum_size) end end end diff --git a/spec/tasks/gitlab/packages/events_rake_spec.rb b/spec/tasks/gitlab/packages/events_rake_spec.rb index ac28f9b5fc2..2c3885855be 100644 --- a/spec/tasks/gitlab/packages/events_rake_spec.rb +++ b/spec/tasks/gitlab/packages/events_rake_spec.rb @@ -7,24 +7,26 @@ RSpec.describe 'gitlab:packages:events namespace rake task' do Rake.application.rake_require 'tasks/gitlab/packages/events' end - describe 'generate' do - subject do - file = double('file') - yml_file = nil + subject do + file = double('file') + yml_file = nil - allow(file).to receive(:<<) { |contents| yml_file = contents } - allow(File).to receive(:open).and_yield(file) + allow(file).to receive(:<<) { |contents| yml_file = contents } + allow(File).to receive(:open).and_yield(file) - run_rake_task('gitlab:packages:events:generate') + run_rake_task("gitlab:packages:events:#{task}") - YAML.safe_load(yml_file) - end + YAML.safe_load(yml_file) + end + + describe 'generate_unique' do + let(:task) { 'generate_unique' } it 'excludes guest events' do expect(subject.find { |event| event['name'].include?("guest") }).to be_nil end - ::Packages::Event::EVENT_SCOPES.keys.each do |event_scope| + Packages::Event::EVENT_SCOPES.keys.each do |event_scope| it "includes includes `#{event_scope}` scope" do expect(subject.find { |event| event['name'].include?(event_scope) }).not_to be_nil end @@ -35,4 +37,19 @@ RSpec.describe 'gitlab:packages:events namespace rake task' do expect(subject.find { |event| event['name'].include?("list_package") }).to be_nil end end + + describe 'generate_guest' do + let(:task) { 'generate_guest' } + + Packages::Event::EVENT_SCOPES.keys.each do |event_scope| + it "includes includes `#{event_scope}` scope" do + expect(subject.find { |event| event.include?(event_scope) }).not_to be_nil + end + end + + it 'excludes some event types' do + expect(subject.find { |event| event.include?("search_package") }).to be_nil + expect(subject.find { |event| event.include?("list_package") }).to be_nil + end + end end