From 559d99e40299e67969023a1afd23d084fbf23ed1 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 11 Feb 2021 18:09:10 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../blob/file_template_selector.js | 2 + .../template_selectors/license_selector.js | 1 + .../deprecated_jquery_dropdown/gl_dropdown.js | 1 + .../javascripts/issue_show/components/app.vue | 5 + .../fields/description_template.vue | 7 +- .../issue_show/components/form.vue | 5 + app/assets/javascripts/issue_show/issue.js | 1 + .../forks/new/components/fork_groups_list.vue | 5 - .../new/components/fork_groups_list_item.vue | 23 +- .../pages/projects/forks/new/index.js | 6 +- .../components/performance_bar_app.vue | 7 + .../javascripts/performance_bar/index.js | 2 + .../javascripts/protected_tags/constants.js | 3 + .../protected_tags/protected_tag_edit.js | 4 +- .../templates/issuable_template_selector.js | 25 +- .../packages_and_registries_controller.rb | 7 + app/finders/license_template_finder.rb | 1 + .../issuables_description_templates_helper.rb | 4 +- app/models/ci/build_trace_chunk.rb | 2 +- app/models/license_template.rb | 9 +- .../sidebar/_packages_settings.html.haml | 5 + .../layouts/nav/sidebar/_group.html.haml | 8 +- app/views/peek/_bar.html.haml | 1 + app/views/projects/forks/new.html.haml | 2 +- .../form/_template_selector.html.haml | 2 +- ...-personal-project-limit-cannot-fork-to.yml | 5 + ...low-or-prevent-duplicate-maven-uploads.yml | 5 + .../btn-default-cicd_for_external_repov.yml | 5 + .../gitlab_ci_trace_read_consistency.yml | 4 +- doc/README.md | 4 +- doc/administration/instance_limits.md | 27 ++- doc/administration/logs.md | 2 + doc/administration/maintenance_mode/index.md | 12 +- .../monitoring/performance/performance_bar.md | 4 + doc/api/merge_requests.md | 3 +- doc/api/project_templates.md | 5 +- doc/ci/pipeline_editor/index.md | 3 +- doc/development/usage_ping.md | 4 +- doc/gitlab-basics/README.md | 49 +--- doc/gitlab-basics/index.md | 49 ++++ doc/integration/elasticsearch.md | 10 +- doc/intro/README.md | 49 +--- doc/intro/index.md | 49 ++++ doc/legal/README.md | 10 +- doc/legal/index.md | 10 + doc/university/README.md | 223 +----------------- doc/university/index.md | 223 ++++++++++++++++++ doc/university/training/index.md | 2 +- .../group_code_coverage_analytics_v13_7.png | Bin 21846 -> 0 bytes .../group_code_coverage_analytics_v13_9.png | Bin 0 -> 93286 bytes doc/user/group/index.md | 12 +- .../group/repositories_analytics/index.md | 19 ++ doc/user/packages/maven_repository/index.md | 15 ++ .../merge_requests/merge_request_approvals.md | 7 +- lib/api/project_templates.rb | 14 +- .../elasticsearch_transport.rb | 15 +- lib/gitlab/instrumentation_helper.rb | 2 + .../redis_adapter_when_peek_enabled.rb | 8 +- lib/gitlab/template/base_template.rb | 7 +- locale/gitlab.pot | 21 +- .../settings/packages_and_registries_spec.rb | 12 +- spec/features/projects/fork_spec.rb | 39 ++- .../user_can_display_performance_bar_spec.rb | 26 ++ .../issue_show/components/app_spec.js | 2 +- .../fields/description_template_spec.js | 6 +- .../issue_show/components/form_spec.js | 7 +- spec/frontend/issue_show/mock_data.js | 1 + .../components/fork_groups_list_item_spec.js | 5 - .../new/components/fork_groups_list_spec.js | 5 +- .../components/performance_bar_app_spec.js | 1 + spec/frontend/performance_bar/index_spec.js | 1 + spec/helpers/issuables_helper_spec.rb | 1 + .../lib/gitlab/instrumentation_helper_spec.rb | 1 + spec/models/license_template_spec.rb | 2 +- .../api/graphql/project/release_spec.rb | 4 +- spec/requests/api/project_templates_spec.rb | 2 +- spec/support/helpers/graphql_helpers.rb | 35 +-- ...e_description_templates_shared_examples.rb | 4 +- 78 files changed, 686 insertions(+), 483 deletions(-) create mode 100644 app/assets/javascripts/protected_tags/constants.js create mode 100644 app/views/groups/sidebar/_packages_settings.html.haml create mode 100644 changelogs/unreleased/264262-users-who-have-reached-their-personal-project-limit-cannot-fork-to.yml create mode 100644 changelogs/unreleased/296895-group-setting-to-allow-or-prevent-duplicate-maven-uploads.yml create mode 100644 changelogs/unreleased/btn-default-cicd_for_external_repov.yml create mode 100644 doc/gitlab-basics/index.md create mode 100644 doc/intro/index.md create mode 100644 doc/legal/index.md create mode 100644 doc/university/index.md delete mode 100644 doc/user/group/img/group_code_coverage_analytics_v13_7.png create mode 100644 doc/user/group/img/group_code_coverage_analytics_v13_9.png diff --git a/app/assets/javascripts/blob/file_template_selector.js b/app/assets/javascripts/blob/file_template_selector.js index 2532aeea989..a5c8050b772 100644 --- a/app/assets/javascripts/blob/file_template_selector.js +++ b/app/assets/javascripts/blob/file_template_selector.js @@ -66,6 +66,8 @@ export default class FileTemplateSelector { reportSelectionName(options) { const opts = options; opts.query = options.selectedObj.name; + opts.data = options.selectedObj; + opts.data.source_template_project_id = options.selectedObj.project_id; this.reportSelection(opts); } diff --git a/app/assets/javascripts/blob/template_selectors/license_selector.js b/app/assets/javascripts/blob/template_selectors/license_selector.js index 4ae5dc70a70..e7fabf18ea1 100644 --- a/app/assets/javascripts/blob/template_selectors/license_selector.js +++ b/app/assets/javascripts/blob/template_selectors/license_selector.js @@ -30,6 +30,7 @@ export default class BlobLicenseSelector extends FileTemplateSelector { const data = { project: this.$dropdown.data('project'), fullname: this.$dropdown.data('fullname'), + source_template_project_id: query.project_id, }; this.reportSelection({ diff --git a/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js b/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js index 99351231520..98858f20518 100644 --- a/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js +++ b/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js @@ -437,6 +437,7 @@ export class GitLabDropdown { groupName = el.data('group'); if (groupName) { selectedIndex = el.data('index'); + this.selectedIndex = selectedIndex; selectedObject = this.renderedData[groupName][selectedIndex]; } else { selectedIndex = el.closest('li').index(); diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index 1720fdf8eec..f5793363913 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -132,6 +132,10 @@ export default { type: String, required: true, }, + projectId: { + type: Number, + required: true, + }, projectNamespace: { type: String, required: true, @@ -419,6 +423,7 @@ export default { :markdown-docs-path="markdownDocsPath" :markdown-preview-path="markdownPreviewPath" :project-path="projectPath" + :project-id="projectId" :project-namespace="projectNamespace" :show-delete-button="showDeleteButton" :can-attach-file="canAttachFile" diff --git a/app/assets/javascripts/issue_show/components/fields/description_template.vue b/app/assets/javascripts/issue_show/components/fields/description_template.vue index a3669cd40bd..b54d85d6247 100644 --- a/app/assets/javascripts/issue_show/components/fields/description_template.vue +++ b/app/assets/javascripts/issue_show/components/fields/description_template.vue @@ -21,6 +21,10 @@ export default { type: String, required: true, }, + projectId: { + type: Number, + required: true, + }, projectNamespace: { type: String, required: true, @@ -49,11 +53,12 @@ export default { diff --git a/app/assets/javascripts/pages/projects/forks/new/index.js b/app/assets/javascripts/pages/projects/forks/new/index.js index 79485859738..a018d7e0926 100644 --- a/app/assets/javascripts/pages/projects/forks/new/index.js +++ b/app/assets/javascripts/pages/projects/forks/new/index.js @@ -1,13 +1,10 @@ import Vue from 'vue'; -import { parseBoolean } from '~/lib/utils/common_utils'; import ForkGroupsList from './components/fork_groups_list.vue'; document.addEventListener('DOMContentLoaded', () => { const mountElement = document.getElementById('fork-groups-mount-element'); - const { endpoint, canCreateProject } = mountElement.dataset; - - const hasReachedProjectLimit = !parseBoolean(canCreateProject); + const { endpoint } = mountElement.dataset; return new Vue({ el: mountElement, @@ -15,7 +12,6 @@ document.addEventListener('DOMContentLoaded', () => { return h(ForkGroupsList, { props: { endpoint, - hasReachedProjectLimit, }, }); }, diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue index 85789cd1fdf..232de605e07 100644 --- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue +++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue @@ -30,6 +30,10 @@ export default { type: String, required: true, }, + statsUrl: { + type: String, + required: true, + }, }, detailedMetrics: [ { @@ -169,6 +173,9 @@ export default { class="ml-auto" @change-current-request="changeCurrentRequest" /> +
+ {{ s__('PerformanceBar|Stats') }} +
diff --git a/app/assets/javascripts/performance_bar/index.js b/app/assets/javascripts/performance_bar/index.js index 0d5c294ea56..9a9b4325fee 100644 --- a/app/assets/javascripts/performance_bar/index.js +++ b/app/assets/javascripts/performance_bar/index.js @@ -30,6 +30,7 @@ const initPerformanceBar = (el) => { requestId: performanceBarData.requestId, peekUrl: performanceBarData.peekUrl, profileUrl: performanceBarData.profileUrl, + statsUrl: performanceBarData.statsUrl, }; }, mounted() { @@ -120,6 +121,7 @@ const initPerformanceBar = (el) => { requestId: this.requestId, peekUrl: this.peekUrl, profileUrl: this.profileUrl, + statsUrl: this.statsUrl, }, on: { 'add-request': this.addRequestManually, diff --git a/app/assets/javascripts/protected_tags/constants.js b/app/assets/javascripts/protected_tags/constants.js new file mode 100644 index 00000000000..3e71ba62877 --- /dev/null +++ b/app/assets/javascripts/protected_tags/constants.js @@ -0,0 +1,3 @@ +import { s__ } from '~/locale'; + +export const FAILED_TO_UPDATE_TAG_MESSAGE = s__('ProjectSettings|Failed to update tag!'); diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit.js b/app/assets/javascripts/protected_tags/protected_tag_edit.js index 6b9506c6dfa..ad702a5c3af 100644 --- a/app/assets/javascripts/protected_tags/protected_tag_edit.js +++ b/app/assets/javascripts/protected_tags/protected_tag_edit.js @@ -1,7 +1,7 @@ -import { s__ } from '~/locale'; import { deprecatedCreateFlash as flash } from '../flash'; import axios from '../lib/utils/axios_utils'; import ProtectedTagAccessDropdown from './protected_tag_access_dropdown'; +import { FAILED_TO_UPDATE_TAG_MESSAGE } from './constants'; export default class ProtectedTagEdit { constructor(options) { @@ -49,7 +49,7 @@ export default class ProtectedTagEdit { this.$allowedToCreateDropdownButton.enable(); window.scrollTo({ top: 0, behavior: 'smooth' }); - flash(s__('ProjectSettings|Failed to update tag!')); + flash(FAILED_TO_UPDATE_TAG_MESSAGE); }); } } diff --git a/app/assets/javascripts/templates/issuable_template_selector.js b/app/assets/javascripts/templates/issuable_template_selector.js index af9979b2502..1bb5e214c2e 100644 --- a/app/assets/javascripts/templates/issuable_template_selector.js +++ b/app/assets/javascripts/templates/issuable_template_selector.js @@ -9,8 +9,7 @@ export default class IssuableTemplateSelector extends TemplateSelector { constructor(...args) { super(...args); - this.projectPath = this.dropdown.data('projectPath'); - this.namespacePath = this.dropdown.data('namespacePath'); + this.projectId = this.dropdown.data('projectId'); this.issuableType = this.$dropdownContainer.data('issuableType'); this.titleInput = $(`#${this.issuableType}_title`); this.templateWarningEl = $('.js-issuable-template-warning'); @@ -81,21 +80,21 @@ export default class IssuableTemplateSelector extends TemplateSelector { } requestFile(query) { + const callback = (currentTemplate) => { + this.currentTemplate = currentTemplate; + this.stopLoadingSpinner(); + this.setInputValueToTemplateContent(); + }; + this.startLoadingSpinner(); - Api.issueTemplate( - this.namespacePath, - this.projectPath, - query.name, + Api.projectTemplate( + this.projectId, this.issuableType, - (err, currentTemplate) => { - this.currentTemplate = currentTemplate; - this.stopLoadingSpinner(); - if (err) return; // Error handled by global AJAX error handler - this.setInputValueToTemplateContent(); - }, + query.name, + { source_template_project_id: query.project_id }, + callback, ); - return; } setInputValueToTemplateContent() { diff --git a/app/controllers/groups/settings/packages_and_registries_controller.rb b/app/controllers/groups/settings/packages_and_registries_controller.rb index dbc1e68742b..0135c03026c 100644 --- a/app/controllers/groups/settings/packages_and_registries_controller.rb +++ b/app/controllers/groups/settings/packages_and_registries_controller.rb @@ -4,11 +4,18 @@ module Groups module Settings class PackagesAndRegistriesController < Groups::ApplicationController before_action :authorize_admin_group! + before_action :verify_packages_enabled! feature_category :package_registry def index end + + private + + def verify_packages_enabled! + render_404 unless group.packages_feature_enabled? + end end end end diff --git a/app/finders/license_template_finder.rb b/app/finders/license_template_finder.rb index 02ab6ec5659..c4cb33235af 100644 --- a/app/finders/license_template_finder.rb +++ b/app/finders/license_template_finder.rb @@ -40,6 +40,7 @@ class LicenseTemplateFinder LicenseTemplate.new( key: license.key, name: license.name, + project: project, nickname: license.nickname, category: (license.featured? ? :Popular : :Other), content: license.content, diff --git a/app/helpers/issuables_description_templates_helper.rb b/app/helpers/issuables_description_templates_helper.rb index 34d02f3a99d..110b3954900 100644 --- a/app/helpers/issuables_description_templates_helper.rb +++ b/app/helpers/issuables_description_templates_helper.rb @@ -16,9 +16,7 @@ module IssuablesDescriptionTemplatesHelper data: issuable_templates(ref_project, issuable.to_ability_name), field_name: 'issuable_template', selected: selected_template(issuable), - project_id: ref_project.id, - project_path: ref_project.path, - namespace_path: ref_project.namespace.full_path + project_id: ref_project.id } } diff --git a/app/models/ci/build_trace_chunk.rb b/app/models/ci/build_trace_chunk.rb index 59403967753..d4f9f78a1ac 100644 --- a/app/models/ci/build_trace_chunk.rb +++ b/app/models/ci/build_trace_chunk.rb @@ -89,7 +89,7 @@ module Ci end def consistent_reads_enabled?(build) - Feature.enabled?(:gitlab_ci_trace_read_consistency, build.project, type: :development, default_enabled: false) + Feature.enabled?(:gitlab_ci_trace_read_consistency, build.project, type: :development, default_enabled: true) end ## diff --git a/app/models/license_template.rb b/app/models/license_template.rb index bd24259984b..548066107c1 100644 --- a/app/models/license_template.rb +++ b/app/models/license_template.rb @@ -12,11 +12,12 @@ class LicenseTemplate (fullname|name\sof\s(author|copyright\sowner)) [\>\}\]]}xi.freeze - attr_reader :key, :name, :category, :nickname, :url, :meta + attr_reader :key, :name, :project, :category, :nickname, :url, :meta - def initialize(key:, name:, category:, content:, nickname: nil, url: nil, meta: {}) + def initialize(key:, name:, project:, category:, content:, nickname: nil, url: nil, meta: {}) @key = key @name = name + @project = project @category = category @content = content @nickname = nickname @@ -24,6 +25,10 @@ class LicenseTemplate @meta = meta end + def project_id + project&.id + end + def popular? category == :Popular end diff --git a/app/views/groups/sidebar/_packages_settings.html.haml b/app/views/groups/sidebar/_packages_settings.html.haml new file mode 100644 index 00000000000..87300ed39ed --- /dev/null +++ b/app/views/groups/sidebar/_packages_settings.html.haml @@ -0,0 +1,5 @@ +- if group_packages_list_nav? + = nav_link(controller: :packages_and_registries) do + = link_to group_settings_packages_and_registries_path(@group), title: _('Packages & Registries') do + %span + = _('Packages & Registries') diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml index 8401111c86c..e99b2f443be 100644 --- a/app/views/layouts/nav/sidebar/_group.html.haml +++ b/app/views/layouts/nav/sidebar/_group.html.haml @@ -117,7 +117,7 @@ %strong.fly-out-top-item-name = _('Kubernetes') - = render_if_exists 'groups/sidebar/packages' + = render 'groups/sidebar/packages' = render 'layouts/nav/sidebar/analytics_links', links: group_analytics_navbar_links(@group, current_user) @@ -177,11 +177,7 @@ %span = _('CI / CD') - - if Feature.enabled?(:packages_and_registries_group_settings, @group) - = nav_link(controller: :packages_and_registries) do - = link_to group_settings_packages_and_registries_path(@group), title: _('Packages & Registries') do - %span - = _('Packages & Registries') + = render 'groups/sidebar/packages_settings' = render_if_exists "groups/ee/settings_nav" diff --git a/app/views/peek/_bar.html.haml b/app/views/peek/_bar.html.haml index 9725f640be9..8914bfab336 100644 --- a/app/views/peek/_bar.html.haml +++ b/app/views/peek/_bar.html.haml @@ -2,5 +2,6 @@ #js-peek{ data: { env: Peek.env, request_id: peek_request_id, + stats_url: ENV.fetch('GITLAB_PERFORMANCE_BAR_STATS_URL', ''), peek_url: "#{peek_routes_path}/results" }, class: Peek.env } diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml index 45d314a1088..ccef28a2cf3 100644 --- a/app/views/projects/forks/new.html.haml +++ b/app/views/projects/forks/new.html.haml @@ -14,5 +14,5 @@ %h5.gl-mt-0.gl-mb-0.gl-ml-3.gl-mr-3 = _("Select a namespace to fork the project") = render 'fork_button', namespace: @own_namespace - #fork-groups-mount-element{ data: { endpoint: new_project_fork_path(@project, format: :json), can_create_project: current_user.can_create_project?.to_s } } + #fork-groups-mount-element{ data: { endpoint: new_project_fork_path(@project, format: :json) } } diff --git a/app/views/shared/issuable/form/_template_selector.html.haml b/app/views/shared/issuable/form/_template_selector.html.haml index 71598b2cd2b..c870bb17a85 100644 --- a/app/views/shared/issuable/form/_template_selector.html.haml +++ b/app/views/shared/issuable/form/_template_selector.html.haml @@ -3,7 +3,7 @@ - return unless issuable && issuable_templates(ref_project, issuable.to_ability_name).any? .issuable-form-select-holder.selectbox.form-group - .js-issuable-selector-wrap{ data: { issuable_type: issuable.to_ability_name, qa_selector: 'template_dropdown' } } + .js-issuable-selector-wrap{ data: { issuable_type: issuable.to_ability_name.pluralize, qa_selector: 'template_dropdown' } } = template_dropdown_tag(issuable) do %ul.dropdown-footer-list %li diff --git a/changelogs/unreleased/264262-users-who-have-reached-their-personal-project-limit-cannot-fork-to.yml b/changelogs/unreleased/264262-users-who-have-reached-their-personal-project-limit-cannot-fork-to.yml new file mode 100644 index 00000000000..d463636130c --- /dev/null +++ b/changelogs/unreleased/264262-users-who-have-reached-their-personal-project-limit-cannot-fork-to.yml @@ -0,0 +1,5 @@ +--- +title: Allow users to fork to a group when their personal namespace is full +merge_request: 53632 +author: +type: fixed diff --git a/changelogs/unreleased/296895-group-setting-to-allow-or-prevent-duplicate-maven-uploads.yml b/changelogs/unreleased/296895-group-setting-to-allow-or-prevent-duplicate-maven-uploads.yml new file mode 100644 index 00000000000..cfa7478ed09 --- /dev/null +++ b/changelogs/unreleased/296895-group-setting-to-allow-or-prevent-duplicate-maven-uploads.yml @@ -0,0 +1,5 @@ +--- +title: Enable group setting to allow or prevent duplicate Maven uploads +merge_request: 53591 +author: +type: added diff --git a/changelogs/unreleased/btn-default-cicd_for_external_repov.yml b/changelogs/unreleased/btn-default-cicd_for_external_repov.yml new file mode 100644 index 00000000000..53ceb4aede1 --- /dev/null +++ b/changelogs/unreleased/btn-default-cicd_for_external_repov.yml @@ -0,0 +1,5 @@ +--- +title: Apply new GitLab UI for buttons in connect repo buttons in new project page +merge_request: 53455 +author: +type: other diff --git a/config/feature_flags/development/gitlab_ci_trace_read_consistency.yml b/config/feature_flags/development/gitlab_ci_trace_read_consistency.yml index c9936a390dc..ee0b4e46924 100644 --- a/config/feature_flags/development/gitlab_ci_trace_read_consistency.yml +++ b/config/feature_flags/development/gitlab_ci_trace_read_consistency.yml @@ -1,8 +1,8 @@ --- name: gitlab_ci_trace_read_consistency introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46976 -rollout_issue_url: +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/320938 milestone: '13.9' type: development group: group::continuous integration -default_enabled: false +default_enabled: true diff --git a/doc/README.md b/doc/README.md index 759d2489c4c..4c4b0cd3a15 100644 --- a/doc/README.md +++ b/doc/README.md @@ -66,7 +66,7 @@ We have the following documentation to rapidly uplift your GitLab knowledge: | Topic | Description | |:--------------------------------------------------------------------------------------------------|:------------| -| [GitLab basics guides](gitlab-basics/README.md) | Start working on the command line and with GitLab. | +| [GitLab basics guides](gitlab-basics/index.md) | Start working on the command line and with GitLab. | | [GitLab workflow overview](https://about.gitlab.com/blog/2016/10/25/gitlab-workflow-an-overview/) | Enhance your workflow with the best of GitLab Workflow. | | [Get started with GitLab CI/CD](ci/quick_start/index.md) | Quickly implement GitLab CI/CD. | | [Auto DevOps](topics/autodevops/index.md) | Learn more about Auto DevOps in GitLab. | @@ -122,5 +122,5 @@ Learn how to contribute to GitLab with the following resources: | Topic | Description | |:------------------------------------------------------------|:------------| | [Development](development/README.md) | How to contribute to GitLab development. | -| [Legal](legal/README.md) | Contributor license agreements. | +| [Legal](legal/index.md) | Contributor license agreements. | | [Writing documentation](development/documentation/index.md) | How to contribute to GitLab Docs. | diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md index 304dab7b010..78e3386ccb3 100644 --- a/doc/administration/instance_limits.md +++ b/doc/administration/instance_limits.md @@ -165,8 +165,6 @@ Read more in the [CI documentation](../ci/yaml/README.md#processing-git-pushes). ## Retention of activity history -> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/21164) in GitLab 8.12. - Activity history for projects and individuals' profiles was limited to one year until [GitLab 11.4](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/52246) when it was extended to two years, and in [GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/issues/33840) to three years. ## Number of embedded metrics @@ -267,9 +265,11 @@ each time a new pipeline is created. An active pipeline is any pipeline in one o If a new pipeline would cause the total number of jobs to exceed the limit, the pipeline will fail with a `job_activity_limit_exceeded` error. -- On GitLab.com different [limits are defined per plan](../user/gitlab_com/index.md#gitlab-cicd) and they affect all projects under that plan. -- On [GitLab Starter](https://about.gitlab.com/pricing/#self-managed) tier or higher self-managed installations, this limit is defined under a `default` plan that affects all projects. - This limit is disabled (`0`) by default. +- GitLab SaaS subscribers have different limits [defined per plan](../user/gitlab_com/index.md#gitlab-cicd), + and they affect all projects under that plan. +- On [GitLab Premium](https://about.gitlab.com/pricing/) self-managed or + higher installations, this limit is defined under a `default` plan that affects all + projects. This limit is disabled (`0`) by default. To set this limit on a self-managed installation, run the following in the [GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session): @@ -292,7 +292,7 @@ any job with an [`environment`](../ci/environments/index.md) specified. The numb of deployments in a pipeline is checked at pipeline creation. Pipelines that have too many deployments fail with a `deployments_limit_exceeded` error. -The default limit is 500 for all [self-managed and GitLab.com plans](https://about.gitlab.com/pricing/). +The default limit is 500 for all [GitLab self-managed and SaaS plans](https://about.gitlab.com/pricing/). To change the limit on a self-managed installation, change the `default` plan's limit with the following [GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session) command: @@ -316,8 +316,11 @@ checked each time a new subscription is created. If a new subscription would cause the total number of subscription to exceed the limit, the subscription will be considered invalid. -- On GitLab.com different [limits are defined per plan](../user/gitlab_com/index.md#gitlab-cicd) and they affect all projects under that plan. -- On [GitLab Starter](https://about.gitlab.com/pricing/#self-managed) tier or higher self-managed installations, this limit is defined under a `default` plan that affects all projects. By default, there is a limit of `2` subscriptions. +- GitLab SaaS subscribers have different limits [defined per plan](../user/gitlab_com/index.md#gitlab-cicd), + and they affect all projects under that plan. +- On [GitLab Premium](https://about.gitlab.com/pricing/) self-managed + or higher installations, this limit is defined under a `default` plan that + affects all projects. By default, there is a limit of `2` subscriptions. To set this limit on a self-managed installation, run the following in the [GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session): @@ -337,11 +340,11 @@ checked each time a new pipeline schedule is created. If a new pipeline schedule would cause the total number of pipeline schedules to exceed the limit, the pipeline schedule will not be created. -On GitLab.com, different limits are [defined per plan](../user/gitlab_com/index.md#gitlab-cicd), +GitLab SaaS subscribers have different limits [defined per plan](../user/gitlab_com/index.md#gitlab-cicd), and they affect all projects under that plan. -On self-managed instances ([GitLab Starter](https://about.gitlab.com/pricing/#self-managed) -or higher tiers), this limit is defined under a `default` plan that affects all +On [GitLab Premium](https://about.gitlab.com/pricing/) self-managed or +higher installations, this limit is defined under a `default` plan that affects all projects. By default, there is a limit of `10` pipeline schedules. To set this limit on a self-managed installation, run the following in the @@ -415,7 +418,7 @@ setting is used: | `ci_max_artifact_size_terraform` | 5 MB ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37018) in GitLab 13.3) | | `ci_max_artifact_size_trace` | 0 | -For example, to set the `ci_max_artifact_size_junit` limit to 10MB on a self-managed +For example, to set the `ci_max_artifact_size_junit` limit to 10 MB on a self-managed installation, run the following in the [GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session): ```ruby diff --git a/doc/administration/logs.md b/doc/administration/logs.md index 5c36f1af960..17ecb324417 100644 --- a/doc/administration/logs.md +++ b/doc/administration/logs.md @@ -93,6 +93,8 @@ which correspond to: 1. `elasticsearch_calls`: total number of calls to Elasticsearch 1. `elasticsearch_duration_s`: total time taken by Elasticsearch calls +1. `elasticsearch_timed_out_count`: total number of calls to Elasticsearch that + timed out and therefore returned partial results ActionCable connection and subscription events are also logged to this file and they follow the same format above. The `method`, `path`, and `format` fields are not applicable, and are always empty. diff --git a/doc/administration/maintenance_mode/index.md b/doc/administration/maintenance_mode/index.md index 0df51a455e1..817cf4488bc 100644 --- a/doc/administration/maintenance_mode/index.md +++ b/doc/administration/maintenance_mode/index.md @@ -19,8 +19,8 @@ operations, such as `git clone` or `git pull`. There are three ways to enable maintenance mode as an administrator: - **Web UI**: - 1. Navigate to the **Admin Area > Application settings > General** and toggle - the maintenance mode. You can optionally add a message for the banner as well. + 1. Go to **Admin Area > Settings > General**, expand **Maintenance mode**, and toggle **Enable maintenance mode**. + You can optionally add a message for the banner as well. 1. Click **Save** for the changes to take effect. - **API**: @@ -41,8 +41,7 @@ There are three ways to enable maintenance mode as an administrator: There are three ways to disable maintenance mode: - **Web UI**: - 1. Navigate to the **Admin Area > Application settings > General** and toggle - the maintenance mode. You can optionally add a message for the banner as well. + 1. Go to **Admin Area > Settings > General**, expand **Maintenance mode**, and toggle **Enable maintenance mode**. 1. Click **Save** for the changes to take effect. - **API**: @@ -85,8 +84,9 @@ All users can log in and out of the GitLab instance. In maintenance mode: -- No new jobs are started. Already running jobs stay in 'running' - status but their logs are no longer updated. +- No new jobs or pipelines, scheduled or otherwise, will start in maintenance mode. +- Those jobs that were already running, will continue to show status as 'running' in the Web UI, even if they finish running on GitLab Runner. +**Note** It is recommended that you restart already running pipelines after maintenance mode is turned off. - If the job has been in 'running' state for longer than the project's time limit, it will **not** time out. - Pipelines cannot be started, retried or canceled in maintenance mode. diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md index 0b67f8c11ba..4f89021b4a6 100644 --- a/doc/administration/monitoring/performance/performance_bar.md +++ b/doc/administration/monitoring/performance/performance_bar.md @@ -6,6 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Performance Bar **(FREE SELF)** +> The **Stats** field [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/271551) in GitLab SaaS 13.9. + You can display the GitLab Performance Bar to see statistics for the performance of a page. When activated, it looks as follows: @@ -53,6 +55,8 @@ From left to right, it displays: - **Request Selector**: a select box displayed on the right-hand side of the Performance Bar which enables you to view these metrics for any requests made while the current page was open. Only the first two requests per unique URL are captured. +- **Stats** (optional): if the `GITLAB_PERFORMANCE_BAR_STATS_URL` environment variable is set, + this URL is displayed in the bar. In GitLab 13.9 and later, used only in GitLab SaaS. ## Request warnings diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index cd447ed1b86..d9bcba96fdc 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -1060,8 +1060,7 @@ POST /projects/:id/merge_requests | `target_branch` | string | yes | The target branch. | | `title` | string | yes | Title of MR. | | `assignee_id` | integer | no | Assignee user ID. | -| `assignee_ids` | integer array | no | The ID of the user(s) to assign the MR to. Set to `0` or provide an empty value to unassign all assignees. | -| `assignee_ids` | integer array | no | The ID of the user(s) to assign the MR to. If set to `0` or left empty, there will be no assignees added. | +| `assignee_ids` | integer array | no | The ID of the user(s) to assign the MR to. Set to `0` or provide an empty value to unassign all assignees. | | `reviewer_ids` | integer array | no | The ID of the user(s) added as a reviewer to the MR. If set to `0` or left empty, there will be no reviewers added. | | `description` | string | no | Description of MR. Limited to 1,048,576 characters. | | `target_project_id` | integer | no | The target project (numeric ID). | diff --git a/doc/api/project_templates.md b/doc/api/project_templates.md index 1f96ee22211..6251d31660c 100644 --- a/doc/api/project_templates.md +++ b/doc/api/project_templates.md @@ -94,14 +94,15 @@ Example response (licenses): ## Get one template of a particular type ```plaintext -GET /projects/:id/templates/:type/:key +GET /projects/:id/templates/:type/:name ``` | Attribute | Type | Required | Description | | ---------- | ------ | -------- | ----------- | | `id` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) | | `type` | string | yes| The type `(dockerfiles|gitignores|gitlab_ci_ymls|licenses|issues|merge_requests)` of the template | -| `key` | string | yes | The key of the template, as obtained from the collection endpoint | +| `name` | string | yes | The key of the template, as obtained from the collection endpoint | +| `source_template_project_id` | integer | no | The project ID where a given template is being stored. This is useful when multiple templates from different projects have the same name. If multiple templates have the same name, the match from `closest ancestor` is returned if `source_template_project_id` is not specified | | `project` | string | no | The project name to use when expanding placeholders in the template. Only affects licenses | | `fullname` | string | no | The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses | diff --git a/doc/ci/pipeline_editor/index.md b/doc/ci/pipeline_editor/index.md index bb61c22d638..430ef9c83c0 100644 --- a/doc/ci/pipeline_editor/index.md +++ b/doc/ci/pipeline_editor/index.md @@ -29,7 +29,7 @@ From the pipeline editor page you can: NOTE: You must already have [a `.gitlab-ci.yml` file](../quick_start/index.md#create-a-gitlab-ciyml-file) -on the default branch (usually "master") of your project to use the editor. +on the default branch (usually `master`) of your project to use the editor. ## Validate CI configuration @@ -67,6 +67,7 @@ reflected in the CI lint. It displays the same results as the existing [CI Lint WARNING: This feature might not be available to you. Check the **version history** note above for details. +It is not accessible if the [pipeline editor is disabled](#enable-or-disable-pipeline-editor). To see a visualization of your `gitlab-ci.yml` configuration, navigate to **CI/CD > Editor** and select the `visualization` tab. The visualization shows all stages and jobs. diff --git a/doc/development/usage_ping.md b/doc/development/usage_ping.md index 752af29f594..3618d18b1bb 100644 --- a/doc/development/usage_ping.md +++ b/doc/development/usage_ping.md @@ -560,9 +560,9 @@ Use one of the following methods to track events: Example: - [Track usage event for incident created in service](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/issues/update_service.rb) + [Track usage event for incident created in service](https://gitlab.com/gitlab-org/gitlab/-/blob/v13.8.3-ee/app/services/issues/update_service.rb#L66) - [Track usage event for incident created in GraphQL](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/mutations/alert_management/update_alert_status.rb) + [Track usage event for incident created in GraphQL](https://gitlab.com/gitlab-org/gitlab/-/blob/v13.8.3-ee/app/graphql/mutations/alert_management/update_alert_status.rb#L16) ```ruby track_usage_event(:incident_management_incident_created, current_user.id) diff --git a/doc/gitlab-basics/README.md b/doc/gitlab-basics/README.md index 8052fd27bb3..c815842480c 100644 --- a/doc/gitlab-basics/README.md +++ b/doc/gitlab-basics/README.md @@ -1,49 +1,8 @@ --- -stage: Create -group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" -comments: false -type: index +redirect_to: 'index.md' --- -# GitLab basics guides **(FREE)** +This document was moved to [another location](index.md). -This section provides resources to help you start working with GitLab and Git by focusing -on the basic features that you will need to use. - -This documentation is split into the following groups: - -- [GitLab-specific functionality](#gitlab-basics), for basic GitLab features. -- [General Git functionality](#working-with-git-from-the-command-line), for working - with Git in conjunction with GitLab. - -## GitLab basics - -The following are guides to basic GitLab functionality: - -- [Create and add your SSH public key](../ssh/README.md), for enabling Git over SSH. -- [Create a project](../user/project/working_with_projects.md#create-a-project), to start using GitLab. -- [Create a group](../user/group/index.md#create-a-new-group), to combine and administer - projects together. -- [Create a branch](create-branch.md), to make changes to files stored in a project's repository. -- [Feature branch workflow](feature_branch_workflow.md). -- [Fork a project](../user/project/working_with_projects.md#fork-a-project), to duplicate projects so they can be worked on in parallel. -- [Add a file](add-file.md), to add new files to a project's repository. -- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue), - to start collaborating within a project. -- [Create a merge request](../user/project/merge_requests/creating_merge_requests.md), to request changes made in a branch - be merged into a project's repository. -- See how these features come together in the [GitLab Flow introduction video](https://youtu.be/InKNIvky2KE) - and [GitLab Flow page](../topics/gitlab_flow.md). - -## Working with Git from the command line - -If you're familiar with Git on the command line, you can interact with your GitLab -projects just as you would with any other Git repository. - -These resources will help you get further acclimated to working on the command line. - -- [Start using Git on the command line](start-using-git.md), for some simple Git commands. -- [Command line basics](command-line-commands.md), to create and edit files using the command line. - -More Git resources are available in the GitLab [Git documentation](../topics/git/index.md). + + diff --git a/doc/gitlab-basics/index.md b/doc/gitlab-basics/index.md new file mode 100644 index 00000000000..8052fd27bb3 --- /dev/null +++ b/doc/gitlab-basics/index.md @@ -0,0 +1,49 @@ +--- +stage: Create +group: Source Code +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +comments: false +type: index +--- + +# GitLab basics guides **(FREE)** + +This section provides resources to help you start working with GitLab and Git by focusing +on the basic features that you will need to use. + +This documentation is split into the following groups: + +- [GitLab-specific functionality](#gitlab-basics), for basic GitLab features. +- [General Git functionality](#working-with-git-from-the-command-line), for working + with Git in conjunction with GitLab. + +## GitLab basics + +The following are guides to basic GitLab functionality: + +- [Create and add your SSH public key](../ssh/README.md), for enabling Git over SSH. +- [Create a project](../user/project/working_with_projects.md#create-a-project), to start using GitLab. +- [Create a group](../user/group/index.md#create-a-new-group), to combine and administer + projects together. +- [Create a branch](create-branch.md), to make changes to files stored in a project's repository. +- [Feature branch workflow](feature_branch_workflow.md). +- [Fork a project](../user/project/working_with_projects.md#fork-a-project), to duplicate projects so they can be worked on in parallel. +- [Add a file](add-file.md), to add new files to a project's repository. +- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue), + to start collaborating within a project. +- [Create a merge request](../user/project/merge_requests/creating_merge_requests.md), to request changes made in a branch + be merged into a project's repository. +- See how these features come together in the [GitLab Flow introduction video](https://youtu.be/InKNIvky2KE) + and [GitLab Flow page](../topics/gitlab_flow.md). + +## Working with Git from the command line + +If you're familiar with Git on the command line, you can interact with your GitLab +projects just as you would with any other Git repository. + +These resources will help you get further acclimated to working on the command line. + +- [Start using Git on the command line](start-using-git.md), for some simple Git commands. +- [Command line basics](command-line-commands.md), to create and edit files using the command line. + +More Git resources are available in the GitLab [Git documentation](../topics/git/index.md). diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md index 964f9e12482..a896f6c674a 100644 --- a/doc/integration/elasticsearch.md +++ b/doc/integration/elasticsearch.md @@ -7,9 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Elasticsearch integration **(PREMIUM SELF)** -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109 "Elasticsearch Merge Request") in GitLab 8.4. -> - Support for [Amazon Elasticsearch](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-gsg.html) was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1305) in GitLab [Starter](https://about.gitlab.com/pricing/) 9.0. -> - [Moved](../subscriptions/bronze_starter.md) to GitLab Premium in 13.9. +> Moved to GitLab Premium in 13.9. This document describes how to enable Advanced Search. After Advanced Search is enabled, you'll have the benefit of fast search response times @@ -179,7 +177,7 @@ To enable Advanced Search, you need to have admin access to GitLab: 1. Navigate to **Admin Area**, then **Settings > Advanced Search**. NOTE: - To see the Advanced Search section, you need an active Starter + To see the Advanced Search section, you need an active GitLab Premium [license](../user/admin_area/license.md). 1. Configure the [Advanced Search settings](#advanced-search-configuration) for @@ -309,8 +307,8 @@ index alias to it which becomes the new `primary` index. At the end, we resume t ### Trigger the reindex via the Advanced Search administration -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34069) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.2. -> - A scheduled index deletion and the ability to cancel it was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38914) in GitLab Starter 13.3. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34069) in GitLab 13.2. +> - A scheduled index deletion and the ability to cancel it was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38914) in GitLab 13.3. Under **Admin Area > Settings > Advanced Search > Elasticsearch zero-downtime reindexing**, click on **Trigger cluster reindexing**. diff --git a/doc/intro/README.md b/doc/intro/README.md index 1ab7553d3a8..c815842480c 100644 --- a/doc/intro/README.md +++ b/doc/intro/README.md @@ -1,49 +1,8 @@ --- -stage: Create -group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" -comments: false +redirect_to: 'index.md' --- -# Get started with GitLab **(FREE)** +This document was moved to [another location](index.md). -## Organize - -Create projects and groups. - -- [Create a new project](../user/project/working_with_projects.md#create-a-project) -- [Create a new group](../user/group/index.md#create-a-new-group) - -## Prioritize - -Create issues, labels, milestones, cast your vote, and review issues. - -- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue) -- [Assign labels to issues](../user/project/labels.md) -- [Use milestones as an overview of your project's tracker](../user/project/milestones/index.md) -- [Use voting to express your like/dislike to issues and merge requests](../user/award_emojis.md) - -## Collaborate - -Create merge requests and review code. - -- [Fork a project and contribute to it](../user/project/repository/forking_workflow.md) -- [Create a new merge request](../user/project/merge_requests/creating_merge_requests.md) -- [Automatically close issues from merge requests](../user/project/issues/managing_issues.md#closing-issues-automatically) -- [Automatically merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md) -- [Revert any commit](../user/project/merge_requests/revert_changes.md) -- [Cherry-pick any commit](../user/project/merge_requests/cherry_pick_changes.md) - -## Test and Deploy - -Use the built-in continuous integration in GitLab. - -- [Get started with GitLab CI/CD](../ci/quick_start/index.md) - -## Install and Update - -Install and update your GitLab installation. - -- [Install GitLab](https://about.gitlab.com/install/) -- [Update GitLab](https://about.gitlab.com/update/) -- [Explore Omnibus GitLab configuration options](https://docs.gitlab.com/omnibus/settings/configuration.html) + + diff --git a/doc/intro/index.md b/doc/intro/index.md new file mode 100644 index 00000000000..1ab7553d3a8 --- /dev/null +++ b/doc/intro/index.md @@ -0,0 +1,49 @@ +--- +stage: Create +group: Source Code +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +comments: false +--- + +# Get started with GitLab **(FREE)** + +## Organize + +Create projects and groups. + +- [Create a new project](../user/project/working_with_projects.md#create-a-project) +- [Create a new group](../user/group/index.md#create-a-new-group) + +## Prioritize + +Create issues, labels, milestones, cast your vote, and review issues. + +- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue) +- [Assign labels to issues](../user/project/labels.md) +- [Use milestones as an overview of your project's tracker](../user/project/milestones/index.md) +- [Use voting to express your like/dislike to issues and merge requests](../user/award_emojis.md) + +## Collaborate + +Create merge requests and review code. + +- [Fork a project and contribute to it](../user/project/repository/forking_workflow.md) +- [Create a new merge request](../user/project/merge_requests/creating_merge_requests.md) +- [Automatically close issues from merge requests](../user/project/issues/managing_issues.md#closing-issues-automatically) +- [Automatically merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md) +- [Revert any commit](../user/project/merge_requests/revert_changes.md) +- [Cherry-pick any commit](../user/project/merge_requests/cherry_pick_changes.md) + +## Test and Deploy + +Use the built-in continuous integration in GitLab. + +- [Get started with GitLab CI/CD](../ci/quick_start/index.md) + +## Install and Update + +Install and update your GitLab installation. + +- [Install GitLab](https://about.gitlab.com/install/) +- [Update GitLab](https://about.gitlab.com/update/) +- [Explore Omnibus GitLab configuration options](https://docs.gitlab.com/omnibus/settings/configuration.html) diff --git a/doc/legal/README.md b/doc/legal/README.md index 371ea53046c..c815842480c 100644 --- a/doc/legal/README.md +++ b/doc/legal/README.md @@ -1,10 +1,8 @@ --- -stage: none -group: unassigned -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments -comments: false +redirect_to: 'index.md' --- -# Legal +This document was moved to [another location](index.md). -Please read through the [GitLab License Agreement](https://gitlab.com/gitlab-org/gitlab/blob/master/CONTRIBUTING.md). + + diff --git a/doc/legal/index.md b/doc/legal/index.md new file mode 100644 index 00000000000..371ea53046c --- /dev/null +++ b/doc/legal/index.md @@ -0,0 +1,10 @@ +--- +stage: none +group: unassigned +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +comments: false +--- + +# Legal + +Please read through the [GitLab License Agreement](https://gitlab.com/gitlab-org/gitlab/blob/master/CONTRIBUTING.md). diff --git a/doc/university/README.md b/doc/university/README.md index 26616312f98..c815842480c 100644 --- a/doc/university/README.md +++ b/doc/university/README.md @@ -1,223 +1,8 @@ --- -stage: none -group: unassigned -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments -comments: false -type: index +redirect_to: 'index.md' --- -# GitLab University +This document was moved to [another location](index.md). -GitLab University is a great place to start when learning about version control with Git and GitLab, as well as other GitLab features. - -If you're looking for a GitLab subscription for _your university_, see our [GitLab for Education](https://about.gitlab.com/solutions/education/) page. - -WARNING: -Some of the content in GitLab University may be out of date and we plan to -[evaluate](https://gitlab.com/gitlab-org/gitlab/-/issues/20403) it. - -The GitLab University curriculum is composed of GitLab videos, screencasts, presentations, projects and external GitLab content hosted on other services and has been organized into the following sections: - -1. [GitLab Beginner](#1-gitlab-beginner). -1. [GitLab Intermediate](#2-gitlab-intermediate). -1. [GitLab Advanced](#3-gitlab-advanced). -1. [External Articles](#4-external-articles). -1. [Resources for GitLab Team Members](#5-resources-for-gitlab-team-members). - -## 1. GitLab Beginner - -### 1.1. Version Control and Git - - - -1. [Version Control Systems](https://docs.google.com/presentation/d/16sX7hUrCZyOFbpvnrAFrg6tVO5_yT98IgdAqOmXwBho/edit#slide=id.g72f2e4906_2_29) -1. [Katacoda: Learn Git Version Control using Interactive Browser-Based Scenarios](https://www.katacoda.com/courses/git) - - - -### 1.2. GitLab Basics - -1. [An Overview of GitLab.com - Video](https://www.youtube.com/watch?v=WaiL5DGEMR4) -1. [Why Use Git and GitLab - Slides](https://docs.google.com/a/gitlab.com/presentation/d/1RcZhFmn5VPvoFu6UMxhMOy7lAsToeBZRjLRn0LIdaNc/edit?usp=drive_web) -1. [GitLab Basics - Article](../gitlab-basics/README.md) -1. [Git and GitLab Basics - Video](https://www.youtube.com/watch?v=03wb9FvO4Ak&index=5&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) -1. [Git and GitLab Basics - Online Course](https://courses.platzi.com/classes/57-git-gitlab/2475-part-233-2/) -1. [Comparison of GitLab Versions](https://about.gitlab.com/features/#compare) - -### 1.3. Your GitLab Account - -1. [Create a GitLab Account - Online Course](https://courses.platzi.com/classes/57-git-gitlab/2434-create-an-account-on-gitlab/) -1. [Create and Add your SSH key to GitLab - Video](https://www.youtube.com/watch?v=54mxyLo3Mqk) - -### 1.4. GitLab Projects - -1. [Repositories, Projects and Groups - Video](https://www.youtube.com/watch?v=4TWfh1aKHHw&index=1&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) -1. [Creating a Project in GitLab - Video](https://www.youtube.com/watch?v=7p0hrpNaJ14) -1. [How to Create Files and Directories](https://about.gitlab.com/blog/2016/02/10/feature-highlight-create-files-and-directories-from-files-page/) -1. [GitLab To-Do List](https://about.gitlab.com/blog/2016/03/02/gitlab-todos-feature-highlight/) -1. [GitLab Work in Progress (WIP) Flag](https://about.gitlab.com/blog/2016/01/08/feature-highlight-wip/) - -### 1.5. Migrating from other Source Control - - - -1. [Migrating from Bitbucket/Stash](../user/project/import/bitbucket.md) -1. [Migrating from GitHub](../user/project/import/github.md) -1. [Migrating from SVN](../user/project/import/svn.md) -1. [Migrating from Fogbugz](../user/project/import/fogbugz.md) - - -### 1.6. The GitLab team - -1. [About GitLab](https://about.gitlab.com/company/) -1. [GitLab Direction](https://about.gitlab.com/direction/) -1. [GitLab Master Plan](https://about.gitlab.com/blog/2016/09/13/gitlab-master-plan/) -1. [Making GitLab Great for Everyone - Video](https://www.youtube.com/watch?v=GGC40y4vMx0) - Response to "Dear GitHub" letter -1. [Using Innersourcing to Improve Collaboration](https://about.gitlab.com/blog/2014/09/05/innersourcing-using-the-open-source-workflow-to-improve-collaboration-within-an-organization/) -1. [The Software Development Market and GitLab - Video](https://www.youtube.com/watch?v=sXlhgPK1NTY&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e&index=6) - [Slides](https://docs.google.com/presentation/d/1vCU-NbZWz8NTNK8Vu3y4zGMAHb5DpC8PE5mHtw1PWfI/edit) -1. [GitLab Resources](https://about.gitlab.com/resources/) - -### 1.7 Community and Support - -1. [Getting Help](https://about.gitlab.com/get-help/) - - Proposing Features and Reporting and Tracking bugs for GitLab - - The GitLab IRC channel, Gitter Chat Room, Community Forum, and Mailing List - - Getting Technical Support - - Being part of our Great Community and Contributing to GitLab -1. [Getting Started with the GitLab Development Kit (GDK)](https://about.gitlab.com/blog/2016/06/08/getting-started-with-gitlab-development-kit/) -1. [GitLab Professional Services](https://about.gitlab.com/services/) - -### 1.8 GitLab Training Material - -1. [Git and GitLab Workshop - Slides](https://docs.google.com/presentation/d/1JzTYD8ij9slejV2-TO-NzjCvlvj6mVn9BORePXNJoMI/edit?usp=drive_web) - -## 2. GitLab Intermediate - -### 2.1 GitLab Pages - -1. [Using any Static Site Generator with GitLab Pages](https://about.gitlab.com/blog/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/) -1. [Securing GitLab Pages with SSL](https://about.gitlab.com/blog/2016/06/24/secure-gitlab-pages-with-startssl/) -1. [GitLab Pages Documentation](../user/project/pages/index.md) - -### 2.2. GitLab Issues - -1. [Markdown in GitLab](../user/markdown.md) -1. [Issues and Merge Requests - Video](https://www.youtube.com/watch?v=raXvuwet78M) -1. [Due Dates and Milestones for GitLab Issues](https://about.gitlab.com/blog/2016/08/05/feature-highlight-set-dates-for-issues/) -1. [How to Use GitLab Labels](https://about.gitlab.com/blog/2016/08/17/using-gitlab-labels/) -1. [Applying GitLab Labels Automatically](https://about.gitlab.com/blog/2016/08/19/applying-gitlab-labels-automatically/) -1. [GitLab Issue Board - Product Page](https://about.gitlab.com/stages-devops-lifecycle/issueboard/) -1. [An Overview of GitLab Issue Board](https://about.gitlab.com/blog/2016/08/22/announcing-the-gitlab-issue-board/) -1. [Designing GitLab Issue Board](https://about.gitlab.com/blog/2016/08/31/designing-issue-boards/) -1. [From Idea to Production with GitLab - Video](https://www.youtube.com/watch?v=25pHyknRgEo&index=14&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) - -### 2.3. Continuous Integration - -1. [Operating Systems, Servers, VMs, Containers and Unix - Video](https://www.youtube.com/watch?v=V61kL6IC-zY&index=8&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) -1. [GitLab CI/CD - Product Page](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/) -1. [Getting started with GitLab and GitLab CI](https://about.gitlab.com/blog/2015/12/14/getting-started-with-gitlab-and-gitlab-ci/) -1. [GitLab Container Registry](https://about.gitlab.com/blog/2016/05/23/gitlab-container-registry/) -1. [GitLab and Docker - Video](https://www.youtube.com/watch?v=ugOrCcbdHko&index=12&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) -1. [How we scale GitLab with built in Docker](https://about.gitlab.com/blog/2016/06/21/how-we-scale-gitlab-by-having-docker-built-in/) -1. [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) -1. [Deployments and Environments](https://about.gitlab.com/blog/2016/08/26/ci-deployment-and-environments/) -1. [Sequential, Parallel or Custom Pipelines](https://about.gitlab.com/blog/2016/07/29/the-basics-of-gitlab-ci/) -1. [Setting up GitLab Runner For Continuous Integration](https://about.gitlab.com/blog/2016/03/01/gitlab-runner-with-docker/) -1. [Setting up GitLab Runner on DigitalOcean](https://about.gitlab.com/blog/2016/04/19/how-to-set-up-gitlab-runner-on-digitalocean/) -1. [Setting up GitLab CI for iOS projects](https://about.gitlab.com/blog/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) -1. [IBM: Continuous Delivery vs Continuous Deployment - Video](https://www.youtube.com/watch?v=igwFj8PPSnw) -1. [Amazon: Transition to Continuous Delivery - Video](https://www.youtube.com/watch?v=esEFaY0FDKc) -1. [TechBeacon: Doing continuous delivery? Focus first on reducing release cycle times](https://techbeacon.com/devops/doing-continuous-delivery-focus-first-reducing-release-cycle-times) -1. See **[Integrations](#39-integrations)** for integrations with other CI services. - -### 2.4. Workflow - -1. [GitLab Flow - Video](https://youtu.be/enMumwvLAug?list=PLFGfElNsQthZnwMUFi6rqkyUZkI00OxIV) -1. [GitLab Flow vs Forking in GitLab - Video](https://www.youtube.com/watch?v=UGotqAUACZA) -1. [GitLab Flow Overview](https://about.gitlab.com/blog/2014/09/29/gitlab-flow/) -1. [Always Start with an Issue](https://about.gitlab.com/blog/2016/03/03/start-with-an-issue/) -1. [GitLab Flow Documentation](../topics/gitlab_flow.md) - -### 2.5. GitLab Comparisons - -1. [GitLab Compared to Other Tools](https://about.gitlab.com/devops-tools/) -1. [Comparing GitLab Terminology](https://about.gitlab.com/blog/2016/01/27/comparing-terms-gitlab-github-bitbucket/) -1. [GitLab Compared to Atlassian (Recording 2016-03-03)](https://youtu.be/Nbzp1t45ERo) -1. [GitLab Position FAQ](https://about.gitlab.com/handbook/positioning-faq/) -1. [Customer review of GitLab with points on why they prefer GitLab](https://www.enovate.co.uk/blog/2015/11/25/gitlab-review) - -## 3. GitLab Advanced - -### 3.1. DevOps - -1. [XebiaLabs: DevOps Terminology](https://digital.ai/glossary) -1. [XebiaLabs: Periodic Table of DevOps Tools](https://digital.ai/periodic-table-of-devops-tools) -1. [Puppet Labs: State of DevOps 2016 - Book](https://puppet.com/resources/report/2016-state-devops-report/) - -### 3.2. Installing GitLab with Omnibus - -1. [What is Omnibus - Video](https://www.youtube.com/watch?v=XTmpKudd-Oo) -1. [How to Install GitLab with Omnibus - Video](https://www.youtube.com/watch?v=Q69YaOjqNhg) -1. [Installing GitLab - Online Course](https://courses.platzi.com/classes/57-git-gitlab/2476-part-0/) -1. [Using a Non-Packaged PostgreSQL Database](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#using-a-non-packaged-postgresql-database-management-server) -1. [Installing GitLab on Microsoft Azure](https://about.gitlab.com/blog/2016/07/13/how-to-setup-a-gitlab-instance-on-microsoft-azure/) -1. [Installing GitLab on Digital Ocean](https://about.gitlab.com/blog/2016/04/27/getting-started-with-gitlab-and-digitalocean/) - -### 3.3. Permissions - -1. [How to Manage Permissions in GitLab EE - Video](https://www.youtube.com/watch?v=DjUoIrkiNuM) - -### 3.4. Large Files - -1. [Big files in Git (Git LFS) - Video](https://www.youtube.com/watch?v=DawznUxYDe4) - -### 3.5. LDAP and Active Directory - -1. [How to Manage LDAP, Active Directory in GitLab - Video](https://www.youtube.com/watch?v=HPMjM-14qa8) - -### 3.6 Custom Languages - -1. [How to add Syntax Highlighting Support for Custom Languages to GitLab - Video](https://youtu.be/6WxTMqatrrA) - -### 3.7. Scalability and High Availability - -1. [Scalability and High Availability - Video](https://www.youtube.com/watch?v=cXRMJJb6sp4&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e&index=2) -1. [High Availability - Video](https://www.youtube.com/watch?v=36KS808u6bE&index=15&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) -1. [High Availability Documentation](https://about.gitlab.com/solutions/reference-architectures/) - -### 3.8 Value Stream Analytics - -1. [GitLab Value Stream Analytics Overview (as of 2016)](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/) -1. [GitLab Value Stream Analytics - Product Page](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/) - -### 3.9. Integrations - - - -1. [How to Integrate Jira and Jenkins with GitLab - Video](https://gitlabmeetings.webex.com/gitlabmeetings/ldr.php?RCID=44b548147a67ab4d8a62274047146415) -1. [How to Integrate Jira with GitLab](../user/project/integrations/jira.md) -1. [How to Integrate Jenkins with GitLab](../integration/jenkins.md) -1. [How to Integrate Bamboo with GitLab](../user/project/integrations/bamboo.md) -1. [How to Integrate Slack with GitLab](../user/project/integrations/slack.md) -1. [How to Integrate Convox with GitLab](https://about.gitlab.com/blog/2016/06/09/continuous-delivery-with-gitlab-and-convox/) -1. [Getting Started with GitLab and Shippable CI](https://about.gitlab.com/blog/2016/05/05/getting-started-gitlab-and-shippable/) - - - -## 4. External Articles - -1. [2011 Wall Street Journal article - Software is Eating the World](https://www.wsj.com/articles/SB10001424053111903480904576512250915629460) -1. [2014 Blog post by Chris Dixon - Software eats software development](https://cdixon.org/2014/04/13/software-eats-software-development/) -1. [2015 Venture Beat article - Actually, Open Source is Eating the World](https://venturebeat.com/2015/12/06/its-actually-open-source-software-thats-eating-the-world/) - -## 5. Resources for GitLab Team Members - -NOTE: -Some content can only be accessed by GitLab team members. - -1. [Sales Path](https://about.gitlab.com/handbook/sales/onboarding/) -1. [User Training](training/user_training.md) -1. [GitLab Flow Training](training/gitlab_flow.md) -1. [Training Topics](training/index.md) -1. [GitLab architecture](../development/architecture.md) -1. [Client Assessment of GitLab versus GitHub](https://docs.google.com/a/gitlab.com/spreadsheets/d/18cRF9Y5I6I7Z_ab6qhBEW55YpEMyU4PitZYjomVHM-M/edit?usp=sharing) + + diff --git a/doc/university/index.md b/doc/university/index.md new file mode 100644 index 00000000000..8b6c2d834f9 --- /dev/null +++ b/doc/university/index.md @@ -0,0 +1,223 @@ +--- +stage: none +group: unassigned +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +comments: false +type: index +--- + +# GitLab University + +GitLab University is a great place to start when learning about version control with Git and GitLab, as well as other GitLab features. + +If you're looking for a GitLab subscription for _your university_, see our [GitLab for Education](https://about.gitlab.com/solutions/education/) page. + +WARNING: +Some of the content in GitLab University may be out of date and we plan to +[evaluate](https://gitlab.com/gitlab-org/gitlab/-/issues/20403) it. + +The GitLab University curriculum is composed of GitLab videos, screencasts, presentations, projects and external GitLab content hosted on other services and has been organized into the following sections: + +1. [GitLab Beginner](#1-gitlab-beginner). +1. [GitLab Intermediate](#2-gitlab-intermediate). +1. [GitLab Advanced](#3-gitlab-advanced). +1. [External Articles](#4-external-articles). +1. [Resources for GitLab Team Members](#5-resources-for-gitlab-team-members). + +## 1. GitLab Beginner + +### 1.1. Version Control and Git + + + +1. [Version Control Systems](https://docs.google.com/presentation/d/16sX7hUrCZyOFbpvnrAFrg6tVO5_yT98IgdAqOmXwBho/edit#slide=id.g72f2e4906_2_29) +1. [Katacoda: Learn Git Version Control using Interactive Browser-Based Scenarios](https://www.katacoda.com/courses/git) + + + +### 1.2. GitLab Basics + +1. [An Overview of GitLab.com - Video](https://www.youtube.com/watch?v=WaiL5DGEMR4) +1. [Why Use Git and GitLab - Slides](https://docs.google.com/a/gitlab.com/presentation/d/1RcZhFmn5VPvoFu6UMxhMOy7lAsToeBZRjLRn0LIdaNc/edit?usp=drive_web) +1. [GitLab Basics - Article](../gitlab-basics/index.md) +1. [Git and GitLab Basics - Video](https://www.youtube.com/watch?v=03wb9FvO4Ak&index=5&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) +1. [Git and GitLab Basics - Online Course](https://courses.platzi.com/classes/57-git-gitlab/2475-part-233-2/) +1. [Comparison of GitLab Versions](https://about.gitlab.com/features/#compare) + +### 1.3. Your GitLab Account + +1. [Create a GitLab Account - Online Course](https://courses.platzi.com/classes/57-git-gitlab/2434-create-an-account-on-gitlab/) +1. [Create and Add your SSH key to GitLab - Video](https://www.youtube.com/watch?v=54mxyLo3Mqk) + +### 1.4. GitLab Projects + +1. [Repositories, Projects and Groups - Video](https://www.youtube.com/watch?v=4TWfh1aKHHw&index=1&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) +1. [Creating a Project in GitLab - Video](https://www.youtube.com/watch?v=7p0hrpNaJ14) +1. [How to Create Files and Directories](https://about.gitlab.com/blog/2016/02/10/feature-highlight-create-files-and-directories-from-files-page/) +1. [GitLab To-Do List](https://about.gitlab.com/blog/2016/03/02/gitlab-todos-feature-highlight/) +1. [GitLab Work in Progress (WIP) Flag](https://about.gitlab.com/blog/2016/01/08/feature-highlight-wip/) + +### 1.5. Migrating from other Source Control + + + +1. [Migrating from Bitbucket/Stash](../user/project/import/bitbucket.md) +1. [Migrating from GitHub](../user/project/import/github.md) +1. [Migrating from SVN](../user/project/import/svn.md) +1. [Migrating from Fogbugz](../user/project/import/fogbugz.md) + + +### 1.6. The GitLab team + +1. [About GitLab](https://about.gitlab.com/company/) +1. [GitLab Direction](https://about.gitlab.com/direction/) +1. [GitLab Master Plan](https://about.gitlab.com/blog/2016/09/13/gitlab-master-plan/) +1. [Making GitLab Great for Everyone - Video](https://www.youtube.com/watch?v=GGC40y4vMx0) - Response to "Dear GitHub" letter +1. [Using Innersourcing to Improve Collaboration](https://about.gitlab.com/blog/2014/09/05/innersourcing-using-the-open-source-workflow-to-improve-collaboration-within-an-organization/) +1. [The Software Development Market and GitLab - Video](https://www.youtube.com/watch?v=sXlhgPK1NTY&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e&index=6) - [Slides](https://docs.google.com/presentation/d/1vCU-NbZWz8NTNK8Vu3y4zGMAHb5DpC8PE5mHtw1PWfI/edit) +1. [GitLab Resources](https://about.gitlab.com/resources/) + +### 1.7 Community and Support + +1. [Getting Help](https://about.gitlab.com/get-help/) + - Proposing Features and Reporting and Tracking bugs for GitLab + - The GitLab IRC channel, Gitter Chat Room, Community Forum, and Mailing List + - Getting Technical Support + - Being part of our Great Community and Contributing to GitLab +1. [Getting Started with the GitLab Development Kit (GDK)](https://about.gitlab.com/blog/2016/06/08/getting-started-with-gitlab-development-kit/) +1. [GitLab Professional Services](https://about.gitlab.com/services/) + +### 1.8 GitLab Training Material + +1. [Git and GitLab Workshop - Slides](https://docs.google.com/presentation/d/1JzTYD8ij9slejV2-TO-NzjCvlvj6mVn9BORePXNJoMI/edit?usp=drive_web) + +## 2. GitLab Intermediate + +### 2.1 GitLab Pages + +1. [Using any Static Site Generator with GitLab Pages](https://about.gitlab.com/blog/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/) +1. [Securing GitLab Pages with SSL](https://about.gitlab.com/blog/2016/06/24/secure-gitlab-pages-with-startssl/) +1. [GitLab Pages Documentation](../user/project/pages/index.md) + +### 2.2. GitLab Issues + +1. [Markdown in GitLab](../user/markdown.md) +1. [Issues and Merge Requests - Video](https://www.youtube.com/watch?v=raXvuwet78M) +1. [Due Dates and Milestones for GitLab Issues](https://about.gitlab.com/blog/2016/08/05/feature-highlight-set-dates-for-issues/) +1. [How to Use GitLab Labels](https://about.gitlab.com/blog/2016/08/17/using-gitlab-labels/) +1. [Applying GitLab Labels Automatically](https://about.gitlab.com/blog/2016/08/19/applying-gitlab-labels-automatically/) +1. [GitLab Issue Board - Product Page](https://about.gitlab.com/stages-devops-lifecycle/issueboard/) +1. [An Overview of GitLab Issue Board](https://about.gitlab.com/blog/2016/08/22/announcing-the-gitlab-issue-board/) +1. [Designing GitLab Issue Board](https://about.gitlab.com/blog/2016/08/31/designing-issue-boards/) +1. [From Idea to Production with GitLab - Video](https://www.youtube.com/watch?v=25pHyknRgEo&index=14&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) + +### 2.3. Continuous Integration + +1. [Operating Systems, Servers, VMs, Containers and Unix - Video](https://www.youtube.com/watch?v=V61kL6IC-zY&index=8&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) +1. [GitLab CI/CD - Product Page](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/) +1. [Getting started with GitLab and GitLab CI](https://about.gitlab.com/blog/2015/12/14/getting-started-with-gitlab-and-gitlab-ci/) +1. [GitLab Container Registry](https://about.gitlab.com/blog/2016/05/23/gitlab-container-registry/) +1. [GitLab and Docker - Video](https://www.youtube.com/watch?v=ugOrCcbdHko&index=12&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) +1. [How we scale GitLab with built in Docker](https://about.gitlab.com/blog/2016/06/21/how-we-scale-gitlab-by-having-docker-built-in/) +1. [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) +1. [Deployments and Environments](https://about.gitlab.com/blog/2016/08/26/ci-deployment-and-environments/) +1. [Sequential, Parallel or Custom Pipelines](https://about.gitlab.com/blog/2016/07/29/the-basics-of-gitlab-ci/) +1. [Setting up GitLab Runner For Continuous Integration](https://about.gitlab.com/blog/2016/03/01/gitlab-runner-with-docker/) +1. [Setting up GitLab Runner on DigitalOcean](https://about.gitlab.com/blog/2016/04/19/how-to-set-up-gitlab-runner-on-digitalocean/) +1. [Setting up GitLab CI for iOS projects](https://about.gitlab.com/blog/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) +1. [IBM: Continuous Delivery vs Continuous Deployment - Video](https://www.youtube.com/watch?v=igwFj8PPSnw) +1. [Amazon: Transition to Continuous Delivery - Video](https://www.youtube.com/watch?v=esEFaY0FDKc) +1. [TechBeacon: Doing continuous delivery? Focus first on reducing release cycle times](https://techbeacon.com/devops/doing-continuous-delivery-focus-first-reducing-release-cycle-times) +1. See **[Integrations](#39-integrations)** for integrations with other CI services. + +### 2.4. Workflow + +1. [GitLab Flow - Video](https://youtu.be/enMumwvLAug?list=PLFGfElNsQthZnwMUFi6rqkyUZkI00OxIV) +1. [GitLab Flow vs Forking in GitLab - Video](https://www.youtube.com/watch?v=UGotqAUACZA) +1. [GitLab Flow Overview](https://about.gitlab.com/blog/2014/09/29/gitlab-flow/) +1. [Always Start with an Issue](https://about.gitlab.com/blog/2016/03/03/start-with-an-issue/) +1. [GitLab Flow Documentation](../topics/gitlab_flow.md) + +### 2.5. GitLab Comparisons + +1. [GitLab Compared to Other Tools](https://about.gitlab.com/devops-tools/) +1. [Comparing GitLab Terminology](https://about.gitlab.com/blog/2016/01/27/comparing-terms-gitlab-github-bitbucket/) +1. [GitLab Compared to Atlassian (Recording 2016-03-03)](https://youtu.be/Nbzp1t45ERo) +1. [GitLab Position FAQ](https://about.gitlab.com/handbook/positioning-faq/) +1. [Customer review of GitLab with points on why they prefer GitLab](https://www.enovate.co.uk/blog/2015/11/25/gitlab-review) + +## 3. GitLab Advanced + +### 3.1. DevOps + +1. [XebiaLabs: DevOps Terminology](https://digital.ai/glossary) +1. [XebiaLabs: Periodic Table of DevOps Tools](https://digital.ai/periodic-table-of-devops-tools) +1. [Puppet Labs: State of DevOps 2016 - Book](https://puppet.com/resources/report/2016-state-devops-report/) + +### 3.2. Installing GitLab with Omnibus + +1. [What is Omnibus - Video](https://www.youtube.com/watch?v=XTmpKudd-Oo) +1. [How to Install GitLab with Omnibus - Video](https://www.youtube.com/watch?v=Q69YaOjqNhg) +1. [Installing GitLab - Online Course](https://courses.platzi.com/classes/57-git-gitlab/2476-part-0/) +1. [Using a Non-Packaged PostgreSQL Database](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#using-a-non-packaged-postgresql-database-management-server) +1. [Installing GitLab on Microsoft Azure](https://about.gitlab.com/blog/2016/07/13/how-to-setup-a-gitlab-instance-on-microsoft-azure/) +1. [Installing GitLab on Digital Ocean](https://about.gitlab.com/blog/2016/04/27/getting-started-with-gitlab-and-digitalocean/) + +### 3.3. Permissions + +1. [How to Manage Permissions in GitLab EE - Video](https://www.youtube.com/watch?v=DjUoIrkiNuM) + +### 3.4. Large Files + +1. [Big files in Git (Git LFS) - Video](https://www.youtube.com/watch?v=DawznUxYDe4) + +### 3.5. LDAP and Active Directory + +1. [How to Manage LDAP, Active Directory in GitLab - Video](https://www.youtube.com/watch?v=HPMjM-14qa8) + +### 3.6 Custom Languages + +1. [How to add Syntax Highlighting Support for Custom Languages to GitLab - Video](https://youtu.be/6WxTMqatrrA) + +### 3.7. Scalability and High Availability + +1. [Scalability and High Availability - Video](https://www.youtube.com/watch?v=cXRMJJb6sp4&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e&index=2) +1. [High Availability - Video](https://www.youtube.com/watch?v=36KS808u6bE&index=15&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) +1. [High Availability Documentation](https://about.gitlab.com/solutions/reference-architectures/) + +### 3.8 Value Stream Analytics + +1. [GitLab Value Stream Analytics Overview (as of 2016)](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/) +1. [GitLab Value Stream Analytics - Product Page](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/) + +### 3.9. Integrations + + + +1. [How to Integrate Jira and Jenkins with GitLab - Video](https://gitlabmeetings.webex.com/gitlabmeetings/ldr.php?RCID=44b548147a67ab4d8a62274047146415) +1. [How to Integrate Jira with GitLab](../user/project/integrations/jira.md) +1. [How to Integrate Jenkins with GitLab](../integration/jenkins.md) +1. [How to Integrate Bamboo with GitLab](../user/project/integrations/bamboo.md) +1. [How to Integrate Slack with GitLab](../user/project/integrations/slack.md) +1. [How to Integrate Convox with GitLab](https://about.gitlab.com/blog/2016/06/09/continuous-delivery-with-gitlab-and-convox/) +1. [Getting Started with GitLab and Shippable CI](https://about.gitlab.com/blog/2016/05/05/getting-started-gitlab-and-shippable/) + + + +## 4. External Articles + +1. [2011 Wall Street Journal article - Software is Eating the World](https://www.wsj.com/articles/SB10001424053111903480904576512250915629460) +1. [2014 Blog post by Chris Dixon - Software eats software development](https://cdixon.org/2014/04/13/software-eats-software-development/) +1. [2015 Venture Beat article - Actually, Open Source is Eating the World](https://venturebeat.com/2015/12/06/its-actually-open-source-software-thats-eating-the-world/) + +## 5. Resources for GitLab Team Members + +NOTE: +Some content can only be accessed by GitLab team members. + +1. [Sales Path](https://about.gitlab.com/handbook/sales/onboarding/) +1. [User Training](training/user_training.md) +1. [GitLab Flow Training](training/gitlab_flow.md) +1. [Training Topics](training/index.md) +1. [GitLab architecture](../development/architecture.md) +1. [Client Assessment of GitLab versus GitHub](https://docs.google.com/a/gitlab.com/spreadsheets/d/18cRF9Y5I6I7Z_ab6qhBEW55YpEMyU4PitZYjomVHM-M/edit?usp=sharing) diff --git a/doc/university/training/index.md b/doc/university/training/index.md index fe29c6a6220..13cf4184560 100644 --- a/doc/university/training/index.md +++ b/doc/university/training/index.md @@ -22,7 +22,7 @@ This section contains the following topics: - [Cherry pick](topics/cherry_picking.md). - [Code review and collaboration with Merge Requests](topics/merge_requests.md). - [Configure your environment](topics/env_setup.md). -- [Explore GitLab](../../gitlab-basics/README.md). +- [Explore GitLab](../../gitlab-basics/index.md). - [Feature branching](topics/feature_branching.md). - [Getting started](topics/getting_started.md). - [GitLab flow](gitlab_flow.md). diff --git a/doc/user/group/img/group_code_coverage_analytics_v13_7.png b/doc/user/group/img/group_code_coverage_analytics_v13_7.png deleted file mode 100644 index 769953b1355f3303db1761ea588c4f48a8e3ccd2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21846 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�>7 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 T^N(vk(LQ~h8`=e$wh#XU>F24D literal 0 HcmV?d00001 diff --git a/doc/user/group/index.md b/doc/user/group/index.md index 0c03d9c4682..1bdaf3db001 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -854,17 +854,7 @@ With [GitLab Issue Analytics](issues_analytics/index.md), you can see a bar char > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/263478) in GitLab 13.6. > - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/276003) in GitLab 13.7. -With [GitLab Repositories Analytics](repositories_analytics/index.md), you can download a CSV of the latest coverage data for all the projects in your group. - -### Check code coverage for all projects - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/263478) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.7. - -See the overall activity of all projects with code coverage with [GitLab Repositories Analytics](repositories_analytics/index.md). - -It displays the current code coverage data available for your projects: - -![Group repositories analytics](img/group_code_coverage_analytics_v13_7.png) +With [GitLab Repositories Analytics](repositories_analytics/index.md), you can view overall activity of all projects with code coverage. ## Dependency Proxy diff --git a/doc/user/group/repositories_analytics/index.md b/doc/user/group/repositories_analytics/index.md index 3204292160c..1cb7c05bb5f 100644 --- a/doc/user/group/repositories_analytics/index.md +++ b/doc/user/group/repositories_analytics/index.md @@ -12,6 +12,25 @@ info: To determine the technical writer assigned to the Stage/Group associated w WARNING: This feature might not be available to you. Check the **version history** note above for details. +![Group repositories analytics](../img/group_code_coverage_analytics_v13_9.png) + +## Current group code coverage + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/263478) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.7. + +The **Analytics > Repositories** group page displays the overall test coverage of all your projects in your group. +In the **Overall activity** section, you can see: + +- The number of projects with coverage reports. +- The average percentage of coverage across all your projects. +- The total number of pipeline jobs that produce coverage reports. + +## Average group test coverage from the last 30 days + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/215140) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.9. + +The **Analytics > Repositories** group page displays the average test coverage of all your projects in your group in a graph for the last 30 days. + ## Latest project test coverage list > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267624) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.6. diff --git a/doc/user/packages/maven_repository/index.md b/doc/user/packages/maven_repository/index.md index c6bf62dfc9a..bae01135170 100644 --- a/doc/user/packages/maven_repository/index.md +++ b/doc/user/packages/maven_repository/index.md @@ -611,6 +611,21 @@ Now navigate to your project's **Packages & Registries** page and view the publi When you publish a package with the same name or version as an existing package, the existing package is overwritten. +#### Do not allow duplicate Maven packages + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/296895) in GitLab Free 13.9. + +To prevent users from publishing duplicate Maven packages, you can use the [GraphQl API](../../../api/graphql/reference/index.md#packagesettings) or the UI. + +In the UI: + +1. For your group, go to **Settings > Packages & Registries**. +1. Expand the **Package Registry** section. +1. Turn on the **Reject duplicates** toggle. +1. Optional. To allow some duplicate packages, in the **Exceptions** box, enter a regex pattern that matches the names of packages you want to allow. + +Your changes are automatically saved. + ## Install a package To install a package from the GitLab Package Registry, you must configure diff --git a/doc/user/project/merge_requests/merge_request_approvals.md b/doc/user/project/merge_requests/merge_request_approvals.md index a201bbc4075..5ee18d50fa0 100644 --- a/doc/user/project/merge_requests/merge_request_approvals.md +++ b/doc/user/project/merge_requests/merge_request_approvals.md @@ -324,12 +324,15 @@ Note that users can edit the approval rules in every merge request and override > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10441) in GitLab 11.10. > - Moved to GitLab Premium in 13.9. -You can prevent users that have committed to a merge request from approving it. To -enable this feature: +You can prevent users who have committed to a merge request from approving it, +though code authors can still approve. To enable this feature: 1. Check the **Prevent MR approvals from users who make commits to the MR.** checkbox. 1. Click **Save changes**. +Read the official Git documentation for an explanation of the +[differences between authors and committers](https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History). + #### Require authentication when approving a merge request > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5981) in GitLab 12.0. diff --git a/lib/api/project_templates.rb b/lib/api/project_templates.rb index f8b5ac65323..fdfdc244cbe 100644 --- a/lib/api/project_templates.rb +++ b/lib/api/project_templates.rb @@ -36,16 +36,22 @@ module API end params do requires :name, type: String, desc: 'The name of the template' - + optional :source_template_project_id, type: Integer, + desc: 'The project id where a given template is being stored. This is useful when multiple templates from different projects have the same name' optional :project, type: String, desc: 'The project name to use when expanding placeholders in the template. Only affects licenses' optional :fullname, type: String, desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses' end get ':id/templates/:type/:name', requirements: TEMPLATE_NAMES_ENDPOINT_REQUIREMENTS do begin - template = TemplateFinder - .build(params[:type], user_project, name: params[:name]) - .execute + template = TemplateFinder.build( + params[:type], + user_project, + { + name: params[:name], + source_template_project_id: params[:source_template_project_id] + } + ).execute rescue ::Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError not_found!('Template') end diff --git a/lib/gitlab/instrumentation/elasticsearch_transport.rb b/lib/gitlab/instrumentation/elasticsearch_transport.rb index 56179eda22d..a1c5bb32fb5 100644 --- a/lib/gitlab/instrumentation/elasticsearch_transport.rb +++ b/lib/gitlab/instrumentation/elasticsearch_transport.rb @@ -9,12 +9,15 @@ module Gitlab start = Time.now headers = (headers || {}) .reverse_merge({ 'X-Opaque-Id': Labkit::Correlation::CorrelationId.current_or_new_id }) - super + response = super ensure if ::Gitlab::SafeRequestStore.active? duration = (Time.now - start) ::Gitlab::Instrumentation::ElasticsearchTransport.increment_request_count + + ::Gitlab::Instrumentation::ElasticsearchTransport.increment_timed_out_count if response&.body&.dig('timed_out') + ::Gitlab::Instrumentation::ElasticsearchTransport.add_duration(duration) ::Gitlab::Instrumentation::ElasticsearchTransport.add_call_details(duration, method, path, params, body) end @@ -25,6 +28,7 @@ module Gitlab ELASTICSEARCH_REQUEST_COUNT = :elasticsearch_request_count ELASTICSEARCH_CALL_DURATION = :elasticsearch_call_duration ELASTICSEARCH_CALL_DETAILS = :elasticsearch_call_details + ELASTICSEARCH_TIMED_OUT_COUNT = :elasticsearch_timed_out_count def self.get_request_count ::Gitlab::SafeRequestStore[ELASTICSEARCH_REQUEST_COUNT] || 0 @@ -49,6 +53,15 @@ module Gitlab ::Gitlab::SafeRequestStore[ELASTICSEARCH_CALL_DURATION] += duration end + def self.increment_timed_out_count + ::Gitlab::SafeRequestStore[ELASTICSEARCH_TIMED_OUT_COUNT] ||= 0 + ::Gitlab::SafeRequestStore[ELASTICSEARCH_TIMED_OUT_COUNT] += 1 + end + + def self.get_timed_out_count + ::Gitlab::SafeRequestStore[ELASTICSEARCH_TIMED_OUT_COUNT] || 0 + end + def self.add_call_details(duration, method, path, params, body) return unless Gitlab::PerformanceBar.enabled_for_request? diff --git a/lib/gitlab/instrumentation_helper.rb b/lib/gitlab/instrumentation_helper.rb index 0d1831ebf9d..61de6b02453 100644 --- a/lib/gitlab/instrumentation_helper.rb +++ b/lib/gitlab/instrumentation_helper.rb @@ -15,6 +15,7 @@ module Gitlab :rugged_duration_s, :elasticsearch_calls, :elasticsearch_duration_s, + :elasticsearch_timed_out_count, *::Gitlab::Memory::Instrumentation::KEY_MAPPING.values, *::Gitlab::Instrumentation::Redis.known_payload_keys, *::Gitlab::Metrics::Subscribers::ActiveRecord::DB_COUNTERS, @@ -79,6 +80,7 @@ module Gitlab payload[:elasticsearch_calls] = elasticsearch_calls payload[:elasticsearch_duration_s] = Gitlab::Instrumentation::ElasticsearchTransport.query_time + payload[:elasticsearch_timed_out_count] = Gitlab::Instrumentation::ElasticsearchTransport.get_timed_out_count end def instrument_external_http(payload) diff --git a/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb b/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb index 133d777fc32..ac5c907465e 100644 --- a/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb +++ b/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb @@ -17,7 +17,7 @@ module Gitlab # to a structured log # rubocop:disable Gitlab/ModuleWithInstanceVariables def enqueue_stats_job(request_id) - return unless gather_stats? + return unless Feature.enabled?(:performance_bar_stats) @client.sadd(GitlabPerformanceBarStatsWorker::STATS_KEY, request_id) @@ -43,12 +43,6 @@ module Gitlab ) end # rubocop:enable Gitlab/ModuleWithInstanceVariables - - def gather_stats? - return unless Feature.enabled?(:performance_bar_stats) - - Gitlab.com? || Gitlab.staging? || !Rails.env.production? - end end end end diff --git a/lib/gitlab/template/base_template.rb b/lib/gitlab/template/base_template.rb index 02b3da54685..0f933a61598 100644 --- a/lib/gitlab/template/base_template.rb +++ b/lib/gitlab/template/base_template.rb @@ -8,6 +8,7 @@ module Gitlab def initialize(path, project = nil, category: nil) @path = path @category = category + @project = project @finder = self.class.finder(project) end @@ -31,6 +32,10 @@ module Gitlab # override with a comment to be placed at the top of the blob. end + def project_id + @project&.id + end + # Present for compatibility with license templates, which can replace text # like `[fullname]` with a user-specified string. This is a no-op for # other templates @@ -76,7 +81,7 @@ module Gitlab end # Defines which strategy will be used to get templates files - # RepoTemplateFinder - Finds templates on project repository, templates are filtered perproject + # RepoTemplateFinder - Finds templates on project repository, templates are filtered per project # GlobalTemplateFinder - Finds templates on gitlab installation source, templates can be used in all projects def finder(project = nil) raise NotImplementedError diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a8116eaf14e..f82b60cfdc1 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -7199,6 +7199,9 @@ msgstr "" msgid "Code" msgstr "" +msgid "Code Coverage: %{coveragePercentage}" +msgstr "" + msgid "Code Coverage: %{coveragePercentage}%{percentSymbol}" msgstr "" @@ -20931,9 +20934,6 @@ msgstr "" msgid "Outdent" msgstr "" -msgid "Overall Activity" -msgstr "" - msgid "Overridden" msgstr "" @@ -21480,6 +21480,9 @@ msgstr "" msgid "PerformanceBar|SQL queries" msgstr "" +msgid "PerformanceBar|Stats" +msgstr "" + msgid "PerformanceBar|trace" msgstr "" @@ -24831,6 +24834,12 @@ msgstr "" msgid "RepositoriesAnalytics|Average Coverage by Job" msgstr "" +msgid "RepositoriesAnalytics|Average coverage" +msgstr "" + +msgid "RepositoriesAnalytics|Average test coverage last 30 days" +msgstr "" + msgid "RepositoriesAnalytics|Coverage" msgstr "" @@ -24858,6 +24867,12 @@ msgstr "" msgid "RepositoriesAnalytics|Latest test coverage results" msgstr "" +msgid "RepositoriesAnalytics|No test coverage to display" +msgstr "" + +msgid "RepositoriesAnalytics|Overall activity" +msgstr "" + msgid "RepositoriesAnalytics|Please select a project or multiple projects to display their most recent test coverage data." msgstr "" diff --git a/spec/features/groups/settings/packages_and_registries_spec.rb b/spec/features/groups/settings/packages_and_registries_spec.rb index e4078fae956..45ea77e3868 100644 --- a/spec/features/groups/settings/packages_and_registries_spec.rb +++ b/spec/features/groups/settings/packages_and_registries_spec.rb @@ -15,9 +15,9 @@ RSpec.describe 'Group Packages & Registries settings' do sign_in(user) end - context 'when the feature flag is off' do + context 'when packges feature is disabled on the group' do before do - stub_feature_flags(packages_and_registries_group_settings: false) + stub_packages_setting(enabled: false) end it 'the menu item is not visible' do @@ -27,9 +27,15 @@ RSpec.describe 'Group Packages & Registries settings' do expect(settings_menu).not_to have_content 'Packages & Registries' end + + it 'renders 404 when navigating to page' do + visit_settings_page + + expect(page).to have_content('Not Found') + end end - context 'when the feature flag is on' do + context 'when packages feature is enabled on the group' do it 'the menu item is visible' do visit group_path(group) diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb index 1e84d1552a1..8d0500f5e13 100644 --- a/spec/features/projects/fork_spec.rb +++ b/spec/features/projects/fork_spec.rb @@ -9,22 +9,45 @@ RSpec.describe 'Project fork' do let(:project) { create(:project, :public, :repository) } before do - sign_in user + sign_in(user) end - it 'allows user to fork project' do + it 'allows user to fork project from the project page' do visit project_path(project) - expect(page).not_to have_css('a.disabled', text: 'Select') + expect(page).not_to have_css('a.disabled', text: 'Fork') end - it 'disables fork button when user has exceeded project limit' do - user.projects_limit = 0 - user.save! + context 'user has exceeded personal project limit' do + before do + user.update!(projects_limit: 0) + end - visit project_path(project) + it 'disables fork button on project page' do + visit project_path(project) - expect(page).to have_css('a.disabled', text: 'Fork') + expect(page).to have_css('a.disabled', text: 'Fork') + end + + context 'with a group to fork to' do + let!(:group) { create(:group).tap { |group| group.add_owner(user) } } + + it 'enables fork button on project page' do + visit project_path(project) + + expect(page).not_to have_css('a.disabled', text: 'Fork') + end + + it 'allows user to fork only to the group on fork page', :js do + visit new_project_fork_path(project) + + to_personal_namespace = find('[data-qa-selector=fork_namespace_button].disabled') + to_group = find(".fork-groups button[data-qa-name=#{group.name}]") + + expect(to_personal_namespace).not_to be_nil + expect(to_group).not_to be_disabled + end + end end context 'forking enabled / disabled in project settings' do diff --git a/spec/features/user_can_display_performance_bar_spec.rb b/spec/features/user_can_display_performance_bar_spec.rb index 9c67523f88f..e74301fb2d8 100644 --- a/spec/features/user_can_display_performance_bar_spec.rb +++ b/spec/features/user_can_display_performance_bar_spec.rb @@ -49,6 +49,10 @@ RSpec.describe 'User can display performance bar', :js do let(:group) { create(:group) } + before do + allow(GitlabPerformanceBarStatsWorker).to receive(:perform_in) + end + context 'when user is logged-out' do before do visit root_path @@ -97,6 +101,28 @@ RSpec.describe 'User can display performance bar', :js do it_behaves_like 'performance bar is enabled by default in development' it_behaves_like 'performance bar can be displayed' + + it 'does not show Stats link by default' do + find('body').native.send_keys('pb') + wait_for_requests + + expect(page).not_to have_link('Stats') + end + + context 'when GITLAB_PERFORMANCE_BAR_STATS_URL environment variable is set' do + let(:stats_url) { 'https://log.gprd.gitlab.net/app/dashboards#/view/' } + + before do + stub_env('GITLAB_PERFORMANCE_BAR_STATS_URL', stats_url) + end + + it 'shows Stats link' do + find('body').native.send_keys('pb') + wait_for_requests + + expect(page).to have_link('Stats', href: stats_url) + end + end end end end diff --git a/spec/frontend/issue_show/components/app_spec.js b/spec/frontend/issue_show/components/app_spec.js index 9be45686d91..a052b856c0e 100644 --- a/spec/frontend/issue_show/components/app_spec.js +++ b/spec/frontend/issue_show/components/app_spec.js @@ -423,7 +423,7 @@ describe('Issuable output', () => { }); it('shows the form if template names request is successful', () => { - const mockData = [{ name: 'Bug' }]; + const mockData = [{ name: 'test', id: 'test', project_path: '/', namespace_path: '/' }]; mock.onGet('/issuable-templates-path').reply(() => Promise.resolve([200, mockData])); return wrapper.vm.requestTemplatesAndShowForm().then(() => { diff --git a/spec/frontend/issue_show/components/fields/description_template_spec.js b/spec/frontend/issue_show/components/fields/description_template_spec.js index 9ebab31f1ad..1193d4f8add 100644 --- a/spec/frontend/issue_show/components/fields/description_template_spec.js +++ b/spec/frontend/issue_show/components/fields/description_template_spec.js @@ -14,8 +14,10 @@ describe('Issue description template component', () => { vm = new Component({ propsData: { formState, - issuableTemplates: [{ name: 'test' }], + issuableTemplates: [{ name: 'test', id: 'test', project_path: '/', namespace_path: '/' }], + projectId: 1, projectPath: '/', + namespacePath: '/', projectNamespace: '/', }, }).$mount(); @@ -23,7 +25,7 @@ describe('Issue description template component', () => { it('renders templates as JSON array in data attribute', () => { expect(vm.$el.querySelector('.js-issuable-selector').getAttribute('data-data')).toBe( - '[{"name":"test"}]', + '[{"name":"test","id":"test","project_path":"/","namespace_path":"/"}]', ); }); diff --git a/spec/frontend/issue_show/components/form_spec.js b/spec/frontend/issue_show/components/form_spec.js index 4e123f606f6..5452a1f45f8 100644 --- a/spec/frontend/issue_show/components/form_spec.js +++ b/spec/frontend/issue_show/components/form_spec.js @@ -19,6 +19,7 @@ describe('Inline edit form component', () => { markdownPreviewPath: '/', markdownDocsPath: '/', projectPath: '/', + projectId: 1, projectNamespace: '/', }; @@ -42,7 +43,11 @@ describe('Inline edit form component', () => { }); it('renders template selector when templates exists', () => { - createComponent({ issuableTemplates: ['test'] }); + createComponent({ + issuableTemplates: [ + { name: 'test', id: 'test', project_path: 'test', namespace_path: 'test' }, + ], + }); expect(vm.$el.querySelector('.js-issuable-selector-wrap')).not.toBeNull(); }); diff --git a/spec/frontend/issue_show/mock_data.js b/spec/frontend/issue_show/mock_data.js index 5a31a550088..fd08c95b454 100644 --- a/spec/frontend/issue_show/mock_data.js +++ b/spec/frontend/issue_show/mock_data.js @@ -52,6 +52,7 @@ export const appProps = { markdownDocsPath: '/', projectNamespace: '/', projectPath: '/', + projectId: 1, issuableTemplateNamesPath: '/issuable-templates-path', zoomMeetingUrl, publishedIncidentUrl, diff --git a/spec/frontend/pages/projects/forks/new/components/fork_groups_list_item_spec.js b/spec/frontend/pages/projects/forks/new/components/fork_groups_list_item_spec.js index b90c07a335b..fbf51cd8852 100644 --- a/spec/frontend/pages/projects/forks/new/components/fork_groups_list_item_spec.js +++ b/spec/frontend/pages/projects/forks/new/components/fork_groups_list_item_spec.js @@ -5,10 +5,6 @@ import ForkGroupsListItem from '~/pages/projects/forks/new/components/fork_group describe('Fork groups list item component', () => { let wrapper; - const DEFAULT_PROPS = { - hasReachedProjectLimit: false, - }; - const DEFAULT_GROUP_DATA = { id: 22, name: 'Gitlab Org', @@ -33,7 +29,6 @@ describe('Fork groups list item component', () => { const createWrapper = (propsData) => { wrapper = shallowMount(ForkGroupsListItem, { propsData: { - ...DEFAULT_PROPS, ...propsData, }, }); diff --git a/spec/frontend/pages/projects/forks/new/components/fork_groups_list_spec.js b/spec/frontend/pages/projects/forks/new/components/fork_groups_list_spec.js index 91740c7ce3b..244f560a87a 100644 --- a/spec/frontend/pages/projects/forks/new/components/fork_groups_list_spec.js +++ b/spec/frontend/pages/projects/forks/new/components/fork_groups_list_spec.js @@ -16,7 +16,6 @@ describe('Fork groups list component', () => { const DEFAULT_PROPS = { endpoint: '/dummy', - hasReachedProjectLimit: false, }; const replyWith = (...args) => axiosMock.onGet(DEFAULT_PROPS.endpoint).reply(...args); @@ -94,10 +93,9 @@ describe('Fork groups list component', () => { it('renders list items for each available group', async () => { const namespaces = [{ name: 'dummy1' }, { name: 'dummy2' }, { name: 'otherdummy' }]; - const hasReachedProjectLimit = true; replyWith(200, { namespaces }); - createWrapper({ hasReachedProjectLimit }); + createWrapper(); await waitForPromises(); @@ -106,7 +104,6 @@ describe('Fork groups list component', () => { namespaces.forEach((namespace, idx) => { expect(wrapper.findAll(ForkGroupsListItem).at(idx).props()).toStrictEqual({ group: namespace, - hasReachedProjectLimit, }); }); }); diff --git a/spec/frontend/performance_bar/components/performance_bar_app_spec.js b/spec/frontend/performance_bar/components/performance_bar_app_spec.js index 417a655093c..67a4259a8e3 100644 --- a/spec/frontend/performance_bar/components/performance_bar_app_spec.js +++ b/spec/frontend/performance_bar/components/performance_bar_app_spec.js @@ -9,6 +9,7 @@ describe('performance bar app', () => { store, env: 'development', requestId: '123', + statsUrl: 'https://log.gprd.gitlab.net/app/dashboards#/view/', peekUrl: '/-/peek/results', profileUrl: '?lineprofiler=true', }, diff --git a/spec/frontend/performance_bar/index_spec.js b/spec/frontend/performance_bar/index_spec.js index 8d9c32b7f12..819b2bcbacf 100644 --- a/spec/frontend/performance_bar/index_spec.js +++ b/spec/frontend/performance_bar/index_spec.js @@ -19,6 +19,7 @@ describe('performance bar wrapper', () => { peekWrapper.setAttribute('data-env', 'development'); peekWrapper.setAttribute('data-request-id', '123'); peekWrapper.setAttribute('data-peek-url', '/-/peek/results'); + peekWrapper.setAttribute('data-stats-url', 'https://log.gprd.gitlab.net/app/dashboards#/view/'); peekWrapper.setAttribute('data-profile-url', '?lineprofiler=true'); mock = new MockAdapter(axios); diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 7c7838e0053..d6b002b47eb 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -209,6 +209,7 @@ RSpec.describe IssuablesHelper do markdownDocsPath: '/help/user/markdown', lockVersion: issue.lock_version, projectPath: @project.path, + projectId: @project.id, projectNamespace: @project.namespace.path, initialTitleHtml: issue.title, initialTitleText: issue.title, diff --git a/spec/lib/gitlab/instrumentation_helper_spec.rb b/spec/lib/gitlab/instrumentation_helper_spec.rb index 5cc911accbb..a5c9cde4c37 100644 --- a/spec/lib/gitlab/instrumentation_helper_spec.rb +++ b/spec/lib/gitlab/instrumentation_helper_spec.rb @@ -16,6 +16,7 @@ RSpec.describe Gitlab::InstrumentationHelper do :rugged_duration_s, :elasticsearch_calls, :elasticsearch_duration_s, + :elasticsearch_timed_out_count, :mem_objects, :mem_bytes, :mem_mallocs, diff --git a/spec/models/license_template_spec.rb b/spec/models/license_template_spec.rb index 515f728f515..fe06d1a357c 100644 --- a/spec/models/license_template_spec.rb +++ b/spec/models/license_template_spec.rb @@ -57,6 +57,6 @@ RSpec.describe LicenseTemplate do end def build_template(content) - described_class.new(key: 'foo', name: 'foo', category: :Other, content: content) + described_class.new(key: 'foo', name: 'foo', project: nil, category: :Other, content: content) end end diff --git a/spec/requests/api/graphql/project/release_spec.rb b/spec/requests/api/graphql/project/release_spec.rb index 963b594a202..72197f00df4 100644 --- a/spec/requests/api/graphql/project/release_spec.rb +++ b/spec/requests/api/graphql/project/release_spec.rb @@ -435,13 +435,13 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do let_it_be_with_reload(:release) { create(:release, project: project) } let(:release_fields) do - query_graphql_field(%{ + %{ milestones { nodes { title } } - }) + } end let(:actual_milestone_title_order) do diff --git a/spec/requests/api/project_templates_spec.rb b/spec/requests/api/project_templates_spec.rb index fc1035fc17d..a424bc62014 100644 --- a/spec/requests/api/project_templates_spec.rb +++ b/spec/requests/api/project_templates_spec.rb @@ -131,7 +131,7 @@ RSpec.describe API::ProjectTemplates do end end - describe 'GET /projects/:id/templates/:type/:key' do + describe 'GET /projects/:id/templates/:type/:name' do it 'returns a specific dockerfile' do get api("/projects/#{public_project.id}/templates/dockerfiles/Binary") diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index d123c51628a..46d0c13dc18 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -125,11 +125,15 @@ module GraphqlHelpers end def graphql_query_for(name, attributes = {}, fields = nil) - <<~QUERY - { - #{query_graphql_field(name, attributes, fields)} - } - QUERY + type = GitlabSchema.types['Query'].fields[GraphqlHelpers.fieldnamerize(name)]&.type + wrap_query(query_graphql_field(name, attributes, fields, type)) + end + + def wrap_query(query) + q = query.to_s + return q if q.starts_with?('{') + + "{ #{q} }" end def graphql_mutation(name, input, fields = nil, &block) @@ -219,12 +223,13 @@ module GraphqlHelpers "#{namerized}#{field_params}" end - def query_graphql_field(name, attributes = {}, fields = nil) + def query_graphql_field(name, attributes = {}, fields = nil, type = nil) + type ||= name.to_s.classify attributes, fields = [nil, attributes] if fields.nil? && !attributes.is_a?(Hash) field = field_with_params(name, attributes) - field + wrap_fields(fields || all_graphql_fields_for(name.to_s.classify)).to_s + field + wrap_fields(fields || all_graphql_fields_for(type)).to_s end def page_info_selection @@ -281,8 +286,8 @@ module GraphqlHelpers allow_high_graphql_recursion allow_high_graphql_transaction_threshold - type = GitlabSchema.types[class_name.to_s] - return "" unless type + type = class_name.respond_to?(:kind) ? class_name : GitlabSchema.types[class_name.to_s] + raise "#{class_name} is not a known type in the GitlabSchema" unless type # We can't guess arguments, so skip fields that require them skip = ->(name, field) { excluded.include?(name) || required_arguments?(field) } @@ -291,7 +296,7 @@ module GraphqlHelpers end def with_signature(variables, query) - %Q[query(#{variables.map(&:sig).join(', ')}) #{query}] + %Q[query(#{variables.map(&:sig).join(', ')}) #{wrap_query(query)}] end def var(type) @@ -309,6 +314,10 @@ module GraphqlHelpers def post_graphql(query, current_user: nil, variables: nil, headers: {}) params = { query: query, variables: serialize_variables(variables) } post api('/', current_user, version: 'graphql'), params: params, headers: headers + + if graphql_errors # Errors are acceptable, but not this one: + expect(graphql_errors).not_to include(a_hash_including('message' => 'Internal server error')) + end end def post_graphql_mutation(mutation, current_user: nil) @@ -378,10 +387,8 @@ module GraphqlHelpers end # Raises an error if no data is found - def graphql_data(body = json_response) - # Note that `json_response` is defined as `let(:json_response)` and - # therefore, in a spec with multiple queries, will only contain data - # from the _first_ query, not subsequent ones + # NB: We use fresh_response_data to support tests that make multiple requests. + def graphql_data(body = fresh_response_data) body['data'] || (raise NoData, graphql_errors(body)) end diff --git a/spec/support/shared_examples/helpers/issuable_description_templates_shared_examples.rb b/spec/support/shared_examples/helpers/issuable_description_templates_shared_examples.rb index 2dcb938d70b..9e8c96d576a 100644 --- a/spec/support/shared_examples/helpers/issuable_description_templates_shared_examples.rb +++ b/spec/support/shared_examples/helpers/issuable_description_templates_shared_examples.rb @@ -23,11 +23,11 @@ RSpec.shared_examples 'project issuable templates' do end it 'returns only md files as issue templates' do - expect(helper.issuable_templates(project, 'issue')).to eq(templates('issue', nil)) + expect(helper.issuable_templates(project, 'issue')).to eq(templates('issue', project)) end it 'returns only md files as merge_request templates' do - expect(helper.issuable_templates(project, 'merge_request')).to eq(templates('merge_request', nil)) + expect(helper.issuable_templates(project, 'merge_request')).to eq(templates('merge_request', project)) end end