diff options
35 files changed, 303 insertions, 155 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index c7da1c5bebc..49fe8eca5a9 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -145,7 +145,7 @@ /doc/api/experiments.md @kpaizee /doc/development/experiment_guide/ @kpaizee /doc/development/snowplow/ @kpaizee -/doc/development/usage_ping/ @kpaizee +/doc/development/service_ping/ @kpaizee /doc/user/admin_area/license.md @kpaizee [Frontend] diff --git a/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql b/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql new file mode 100644 index 00000000000..68ff22566e3 --- /dev/null +++ b/app/assets/javascripts/repository/mutations/lock_path.mutation.graphql @@ -0,0 +1,12 @@ +mutation toggleLock($projectPath: ID!, $filePath: String!, $lock: Boolean!) { + projectSetLocked(input: { projectPath: $projectPath, filePath: $filePath, lock: $lock }) { + project { + pathLocks { + nodes { + path + } + } + } + errors + } +} diff --git a/app/models/user.rb b/app/models/user.rb index 98281102458..4d3d635ab07 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1013,6 +1013,8 @@ class User < ApplicationRecord # Returns a relation of groups the user has access to, including their parent # and child groups (recursively). def all_expanded_groups + return groups if groups.empty? + Gitlab::ObjectHierarchy.new(groups).all_objects end diff --git a/app/serializers/ci/pipeline_entity.rb b/app/serializers/ci/pipeline_entity.rb index fa0e904fbde..a5af543f49f 100644 --- a/app/serializers/ci/pipeline_entity.rb +++ b/app/serializers/ci/pipeline_entity.rb @@ -7,6 +7,7 @@ class Ci::PipelineEntity < Grape::Entity delegate :name, :failure_reason, to: :presented_pipeline expose :id + expose :iid expose :user, using: UserEntity expose :active?, as: :active diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb index a90c22c7de5..ca479669ca4 100644 --- a/app/services/projects/update_pages_service.rb +++ b/app/services/projects/update_pages_service.rb @@ -37,14 +37,13 @@ module Projects job.run! end - raise InvalidStateError, 'missing pages artifacts' unless build.artifacts? - raise InvalidStateError, 'build SHA is outdated for this ref' unless latest? + validate_state! + validate_max_size! + validate_max_entries! build.artifacts_file.use_file do |artifacts_path| deploy_to_legacy_storage(artifacts_path) - create_pages_deployment(artifacts_path, build) - success end rescue InvalidStateError => e @@ -92,8 +91,10 @@ module Projects # Check if we did extract public directory archive_public_path = File.join(tmp_path, PUBLIC_DIR) + raise InvalidStateError, 'pages miss the public folder' unless Dir.exist?(archive_public_path) - raise InvalidStateError, 'build SHA is outdated for this ref' unless latest? + + validate_outdated_sha! deploy_page!(archive_public_path) end @@ -108,15 +109,6 @@ module Projects end def extract_zip_archive!(artifacts_path, temp_path) - raise InvalidStateError, 'missing artifacts metadata' unless build.artifacts_metadata? - - # Calculate page size after extract - public_entry = build.artifacts_metadata_entry(PUBLIC_DIR + '/', recursive: true) - - if public_entry.total_size > max_size - raise InvalidStateError, "artifacts for pages are too large: #{public_entry.total_size}" - end - SafeZip::Extract.new(artifacts_path) .extract(directories: [PUBLIC_DIR], to: temp_path) rescue SafeZip::Extract::Error => e @@ -151,10 +143,6 @@ module Projects end def create_pages_deployment(artifacts_path, build) - # we're using the full archive and pages daemon needs to read it - # so we want the total count from entries, not only "public/" directory - # because it better approximates work we need to do before we can serve the site - entries_count = build.artifacts_metadata_entry("", recursive: true).entries.count sha256 = build.job_artifacts_archive.file_sha256 deployment = nil @@ -163,7 +151,7 @@ module Projects file_count: entries_count, file_sha256: sha256) - raise InvalidStateError, 'build SHA is outdated for this ref' unless latest? + validate_outdated_sha! project.update_pages_deployment!(deployment) end @@ -175,29 +163,6 @@ module Projects ) end - def latest? - # check if sha for the ref is still the most recent one - # this helps in case when multiple deployments happens - sha == latest_sha - end - - def blocks - # Calculate dd parameters: we limit the size of pages - 1 + max_size / BLOCK_SIZE - end - - def max_size_from_settings - Gitlab::CurrentSettings.max_pages_size.megabytes - end - - def max_size - max_pages_size = max_size_from_settings - - return ::Gitlab::Pages::MAX_SIZE if max_pages_size == 0 - - max_pages_size - end - def tmp_path @tmp_path ||= File.join(::Settings.pages.path, TMP_EXTRACT_PATH) end @@ -262,6 +227,65 @@ module Projects def tmp_dir_prefix "project-#{project.id}-build-#{build.id}-" end + + def validate_state! + raise InvalidStateError, 'missing pages artifacts' unless build.artifacts? + raise InvalidStateError, 'missing artifacts metadata' unless build.artifacts_metadata? + + validate_outdated_sha! + end + + def validate_outdated_sha! + raise InvalidStateError, 'build SHA is outdated for this ref' unless latest? + end + + def latest? + # check if sha for the ref is still the most recent one + # this helps in case when multiple deployments happens + sha == latest_sha + end + + def validate_max_size! + if total_size > max_size + raise InvalidStateError, "artifacts for pages are too large: #{total_size}" + end + end + + # Calculate page size after extract + def total_size + @total_size ||= build.artifacts_metadata_entry(PUBLIC_DIR + '/', recursive: true).total_size + end + + def max_size_from_settings + Gitlab::CurrentSettings.max_pages_size.megabytes + end + + def max_size + max_pages_size = max_size_from_settings + + return ::Gitlab::Pages::MAX_SIZE if max_pages_size == 0 + + max_pages_size + end + + def validate_max_entries! + if pages_file_entries_limit > 0 && entries_count > pages_file_entries_limit + raise InvalidStateError, "pages site contains #{entries_count} file entries, while limit is set to #{pages_file_entries_limit}" + end + end + + def entries_count + # we're using the full archive and pages daemon needs to read it + # so we want the total count from entries, not only "public/" directory + # because it better approximates work we need to do before we can serve the site + @entries_count = build.artifacts_metadata_entry("", recursive: true).entries.count + end + + def pages_file_entries_limit + return 0 unless Feature.enabled?(:pages_limit_entries_count, project, default_enabled: :yaml) + + project.actual_limits.pages_file_entries + end end end diff --git a/app/views/admin/application_settings/_pages.html.haml b/app/views/admin/application_settings/_pages.html.haml index 5d6443825b7..d14c8cffcc7 100644 --- a/app/views/admin/application_settings/_pages.html.haml +++ b/app/views/admin/application_settings/_pages.html.haml @@ -3,42 +3,48 @@ %fieldset .form-group - = f.label :max_pages_size, _('Maximum size of pages (MB)'), class: 'label-bold' - = f.number_field :max_pages_size, class: 'form-control gl-form-input' - .form-text.text-muted - = _("0 for unlimited") - .form-group .form-check = f.check_box :pages_domain_verification_enabled, class: 'form-check-input' = f.label :pages_domain_verification_enabled, class: 'form-check-label' do - = _("Require users to prove ownership of custom domains") + = s_("AdminSettings|Require users to prove ownership of custom domains") .form-text.text-muted - = _("Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled") - = link_to sprite_icon('question-o'), help_page_path('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: '4-verify-the-domains-ownership') + - pages_link_url = help_page_path('administration/pages/index', anchor: 'custom-domain-verification') + - pages_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: pages_link_url } + = s_('AdminSettings|Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled. %{link_start}Learn more.%{link_end}').html_safe % { link_start: pages_link_start, link_end: '</a>'.html_safe } - if Gitlab.config.pages.access_control .form-group .form-check = f.check_box :force_pages_access_control, class: 'form-check-input' = f.label :force_pages_access_control, class: 'form-check-label' do - = _("Disable public access to Pages sites") + = s_("AdminSettings|Disable public access to Pages sites") .form-text.text-muted - = _("Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance.") - = link_to sprite_icon('question-o'), help_page_path('administration/pages/index.md', anchor: 'disabling-public-access-to-all-pages-websites') + - pages_link_url = help_page_path('administration/pages/index', anchor: 'disable-public-access-to-all-pages-sites') + - pages_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: pages_link_url } + = s_("AdminSettings|Select to disable public access for Pages sites, which requires users to sign in for access to the Pages sites in your instance. %{link_start}Learn more.%{link_end}").html_safe % { link_start: pages_link_start, link_end: '</a>'.html_safe } + .form-group + = f.label :max_pages_size, _('Maximum size of pages (MB)'), class: 'label-bold' + = f.number_field :max_pages_size, class: 'form-control gl-form-input' + .form-text.text-muted + - pages_link_url = help_page_path('administration/pages/index', anchor: 'set-global-maximum-pages-size-per-project') + - pages_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: pages_link_url } + = s_('AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}').html_safe % { link_start: pages_link_start, link_end: '</a>'.html_safe } %h5 - = _("Configure Let's Encrypt") + = s_("AdminSettings|Configure Let's Encrypt") %p - lets_encrypt_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: "https://letsencrypt.org/" } - = _("%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} is a free, automated, and open certificate authority (CA), that give digital certificates in order to enable HTTPS (SSL/TLS) for websites.").html_safe % { lets_encrypt_link_start: lets_encrypt_link_start, lets_encrypt_link_end: '</a>'.html_safe } - .form-group - = f.label :lets_encrypt_notification_email, _("Email"), class: 'label-bold' - = f.text_field :lets_encrypt_notification_email, class: 'form-control gl-form-input' - .form-text.text-muted - = _("A Let's Encrypt account will be configured for this GitLab installation using your email address. You will receive emails to warn of expiring certificates.") - .form-group - .form-check - = f.check_box :lets_encrypt_terms_of_service_accepted, class: 'form-check-input' - = f.label :lets_encrypt_terms_of_service_accepted, class: 'form-check-label' do - - terms_of_service_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: lets_encrypt_terms_of_service_admin_application_settings_path } - = _("I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end} (PDF)").html_safe % { link_start: terms_of_service_link_start, link_end: '</a>'.html_safe } + = _("%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} is a free, automated, and open certificate authority (CA) that issues digital certificates to enable HTTPS (SSL/TLS) for sites.").html_safe % { lets_encrypt_link_start: lets_encrypt_link_start, lets_encrypt_link_end: '</a>'.html_safe } + .form-group + = f.label :lets_encrypt_notification_email, s_("AdminSettings|Let's Encrypt email"), class: 'label-bold' + = f.text_field :lets_encrypt_notification_email, class: 'form-control gl-form-input' + .form-text.text-muted + - pages_link_url = help_page_path('administration/pages/index', anchor: 'lets-encrypt-integration') + - pages_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: pages_link_url } + = s_("AdminSettings|A Let's Encrypt account will be configured for this GitLab instance using this email address. You will receive emails to warn of expiring certificates. %{link_start}Learn more.%{link_end}").html_safe % { link_start: pages_link_start, link_end: '</a>'.html_safe } + .form-group + .form-check + = f.check_box :lets_encrypt_terms_of_service_accepted, class: 'form-check-input' + = f.label :lets_encrypt_terms_of_service_accepted, class: 'form-check-label' do + - terms_of_service_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: lets_encrypt_terms_of_service_admin_application_settings_path } + = s_("AdminSettings|I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end} (PDF).").html_safe % { link_start: terms_of_service_link_start, link_end: '</a>'.html_safe } = f.submit _('Save changes'), class: "gl-button btn btn-confirm" diff --git a/app/views/admin/application_settings/preferences.html.haml b/app/views/admin/application_settings/preferences.html.haml index 08e5aaefb39..9711c335802 100644 --- a/app/views/admin/application_settings/preferences.html.haml +++ b/app/views/admin/application_settings/preferences.html.haml @@ -43,7 +43,7 @@ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' } = expanded_by_default? ? _('Collapse') : _('Expand') %p - = _('Size and domain settings for static websites') + = s_('AdminSettings|Size and domain settings for Pages static sites.') .settings-content = render 'pages' diff --git a/app/views/projects/mirrors/_mirror_repos_push.html.haml b/app/views/projects/mirrors/_mirror_repos_push.html.haml index 04f44f4748e..b3e0f71bf19 100644 --- a/app/views/projects/mirrors/_mirror_repos_push.html.haml +++ b/app/views/projects/mirrors/_mirror_repos_push.html.haml @@ -11,5 +11,5 @@ = check_box_tag :keep_divergent_refs, '1', false, class: 'js-mirror-keep-divergent-refs form-check-input' = label_tag :keep_divergent_refs, _('Keep divergent refs'), class: 'form-check-label' .form-text.text-muted - = _('By default, if any ref (branch, tag, or commit) on the remote mirror has diverged from the local repository, the entire push will fail, and nothing will be updated. Choose this option to override this behavior. After the mirror is created, this can only be modified via the API.') - = link_to _('Learn more.'), help_page_path('user/project/repository/repository_mirroring', anchor: 'keep-divergent-refs'), target: '_blank', rel: 'noopener noreferrer' + - link_opening_tag = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe + = html_escape(_('Do not force push over diverged refs. After the mirror is created, this setting can only be modified using the API. %{mirroring_docs_link_start}Learn more about this option%{link_closing_tag} and %{mirroring_api_docs_link_start}the API.%{link_closing_tag}')) % { mirroring_docs_link_start: link_opening_tag % {url: help_page_path('user/project/repository/repository_mirroring', anchor: 'keep-divergent-refs')}, mirroring_api_docs_link_start: link_opening_tag % {url: help_page_path('api/remote_mirrors')}, link_closing_tag: '</a>'.html_safe } diff --git a/bin/secpick b/bin/secpick index 07bac9270c9..2512175a0e0 100755 --- a/bin/secpick +++ b/bin/secpick @@ -39,7 +39,7 @@ module Secpick ["git fetch #{@options[:remote]} #{stable_branch}", "git checkout -B #{source_branch} #{@options[:remote]}/#{stable_branch} --no-track", "git cherry-pick #{@options[:sha]}", - "git push #{@options[:remote]} #{source_branch}", + "git push #{@options[:remote]} #{source_branch} --no-verify", "git checkout #{@options[:branch]}"] end diff --git a/config/feature_categories.yml b/config/feature_categories.yml index 4177978ffea..01446f931cf 100644 --- a/config/feature_categories.yml +++ b/config/feature_categories.yml @@ -9,7 +9,6 @@ --- - accessibility_testing - advanced_deployments -- api - attack_emulation - audit_events - audit_reports @@ -65,14 +64,12 @@ - infrastructure - infrastructure_as_code - insider_threat -- insights - integrations - intel_code_security - interactive_application_security_testing - internationalization - issue_tracking - jenkins_importer -- jira_importer - kubernetes_management - license - license_compliance diff --git a/config/feature_flags/development/pages_limit_entries_count.yml b/config/feature_flags/development/pages_limit_entries_count.yml new file mode 100644 index 00000000000..2bcd00e6fa2 --- /dev/null +++ b/config/feature_flags/development/pages_limit_entries_count.yml @@ -0,0 +1,8 @@ +--- +name: pages_limit_entries_count +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64925/diffs +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334765 +milestone: '14.1' +type: development +group: group::release +default_enabled: false diff --git a/db/migrate/20210611082822_add_pages_file_entries_to_plan_limits.rb b/db/migrate/20210611082822_add_pages_file_entries_to_plan_limits.rb new file mode 100644 index 00000000000..ef2177fa9ce --- /dev/null +++ b/db/migrate/20210611082822_add_pages_file_entries_to_plan_limits.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddPagesFileEntriesToPlanLimits < ActiveRecord::Migration[6.1] + def change + add_column(:plan_limits, :pages_file_entries, :integer, default: 200_000, null: false) + end +end diff --git a/db/schema_migrations/20210611082822 b/db/schema_migrations/20210611082822 new file mode 100644 index 00000000000..474adb00646 --- /dev/null +++ b/db/schema_migrations/20210611082822 @@ -0,0 +1 @@ +28b31b6e8aba1b8feec2b9a29b5f91f7145431be5d8b9875bddb8183f89700f7
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index ab407bc0cea..0a6ee767c36 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -16505,7 +16505,8 @@ CREATE TABLE plan_limits ( ci_daily_pipeline_schedule_triggers integer DEFAULT 0 NOT NULL, ci_max_artifact_size_running_container_scanning integer DEFAULT 0 NOT NULL, ci_max_artifact_size_cluster_image_scanning integer DEFAULT 0 NOT NULL, - ci_jobs_trace_size_limit integer DEFAULT 100 NOT NULL + ci_jobs_trace_size_limit integer DEFAULT 100 NOT NULL, + pages_file_entries integer DEFAULT 200000 NOT NULL ); CREATE SEQUENCE plan_limits_id_seq diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md index bd1be0981ce..e914afde79f 100644 --- a/doc/administration/instance_limits.md +++ b/doc/administration/instance_limits.md @@ -457,6 +457,21 @@ installation, run the following in the [GitLab Rails console](operations/rails_c Plan.default.actual_limits.update!(ci_max_artifact_size_junit: 10) ``` +### Number of files per GitLab Pages web-site + +The total number of file entries (including directories and symlinks) is limited to `100000` per +GitLab Pages website. + +This is the default limit for all [GitLab self-managed and SaaS plans](https://about.gitlab.com/pricing/). + +You can update the limit in your self-managed instance using the +[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session). +For example, to change the limit to `100`: + +```ruby +Plan.default.actual_limits.update!(pages_file_entries: 100) +``` + ### Number of registered runners per scope > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/321368) in GitLab 13.12. diff --git a/doc/administration/pages/img/lets_encrypt_integration_v12_1.png b/doc/administration/pages/img/lets_encrypt_integration_v12_1.png Binary files differdeleted file mode 100644 index 0f3ca25ce55..00000000000 --- a/doc/administration/pages/img/lets_encrypt_integration_v12_1.png +++ /dev/null diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md index f11c6c4dfbc..5aeb3eaef7f 100644 --- a/doc/administration/pages/index.md +++ b/doc/administration/pages/index.md @@ -407,17 +407,15 @@ verification requirement: allows users to add Let's Encrypt SSL certificates for GitLab Pages sites served under a custom domain. -To enable it, you must: +To enable it: 1. Choose an email address on which you want to receive notifications about expiring domains. 1. On the top bar, select **Menu >** **{admin}** **Admin**. 1. On the left sidebar, select **Settings > Preferences**. 1. Expand **Pages**. -1. Enter the email address for receiving notifications and accept Let's Encrypt's Terms of Service as shown below. +1. Enter the email address for receiving notifications and accept Let's Encrypt's Terms of Service. 1. Select **Save changes**. -![Let's Encrypt settings](img/lets_encrypt_integration_v12_1.png) - ### Access control > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/33422) in GitLab 11.5. @@ -466,6 +464,7 @@ The scope to use for authentication must match the GitLab Pages OAuth applicatio pre-existing applications must modify the GitLab Pages OAuth application. Follow these steps to do this: +1. Enable [access control](#access-control). 1. On the top bar, select **Menu >** **{admin}** **Admin**. 1. On the left sidebar, select **Settings > Applications**. 1. Expand **GitLab Pages**. @@ -473,7 +472,7 @@ this: `read_api`). 1. Select **Save changes**. -#### Disabling public access to all Pages websites +#### Disable public access to all Pages sites > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32095) in GitLab 12.7. @@ -662,6 +661,16 @@ Follow the steps below to configure the proxy listener of GitLab Pages. 1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure). +## Set global maximum pages size per project **(FREE SELF)** + +To set the global maximum pages size for a project: + +1. On the top bar, select **Menu >** **{admin}** **Admin**. +1. On the left sidebar, select **Settings > Preferences**. +1. Expand **Pages**. +1. Edit the **Maximum size of pages**. +1. Select **Save changes**. + ## Override maximum pages size per project or group **(PREMIUM SELF)** > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16610) in GitLab 12.7. diff --git a/doc/api/discussions.md b/doc/api/discussions.md index 9e9b9dcc901..1c22f261e57 100644 --- a/doc/api/discussions.md +++ b/doc/api/discussions.md @@ -1214,13 +1214,13 @@ Parameters: | Attribute | Type | Required | Description | | ------------------------- | -------------- | -------- | ----------- | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) | -| `commit_id` | integer | yes | The ID of a commit | +| `commit_id` | string | yes | The SHA of a commit | | `body` | string | yes | The content of the thread | | `created_at` | string | no | Date time string, ISO 8601 formatted, such as `2016-03-11T03:45:40Z` (requires administrator or project/group owner rights) | | `position` | hash | no | Position when creating a diff note | -| `position[base_sha]` | string | yes | Base commit SHA in the source branch | -| `position[start_sha]` | string | yes | SHA referencing commit in target branch | -| `position[head_sha]` | string | yes | SHA referencing HEAD of this commit | +| `position[base_sha]` | string | yes | SHA of the parent commit| +| `position[start_sha]` | string | yes | SHA of the parent commit | +| `position[head_sha]` | string | yes | The SHA of this commit (same as `commit_id`) | | `position[position_type]` | string | yes | Type of the position reference', allowed values: `text` or `image` | | `position[new_path]` | string | no | File path after change | | `position[new_line]` | integer | no | Line number after change | @@ -1235,6 +1235,10 @@ Parameters: curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/commits/11/discussions?body=comment" ``` +The rules for creating the API request are the same as when +[creating a new thread in the merge request diff](#create-a-new-thread-in-the-merge-request-diff), +with the exception of `base_sha`, `start_sha`, and `head_sha` attributes. + ### Add note to existing commit thread Adds a new note to the thread. diff --git a/doc/api/pipelines.md b/doc/api/pipelines.md index 4b361da6070..ca820d41a60 100644 --- a/doc/api/pipelines.md +++ b/doc/api/pipelines.md @@ -52,6 +52,7 @@ Example of response [ { "id": 47, + "iid": 12, "project_id": 1, "status": "pending", "ref": "new-pipeline", @@ -62,6 +63,7 @@ Example of response }, { "id": 48, + "iid": 13, "project_id": 1, "status": "pending", "ref": "new-pipeline", @@ -93,6 +95,7 @@ Example of response ```json { "id": 46, + "iid": 11, "project_id": 1, "status": "success", "ref": "main", @@ -281,6 +284,7 @@ Example of response ```json { "id": 61, + "iid": 21, "project_id": 1, "sha": "384c444e840a515b23f21915ee5766b87068a70d", "ref": "main", @@ -328,6 +332,7 @@ Response: ```json { "id": 46, + "iid": 11, "project_id": 1, "status": "pending", "ref": "main", @@ -375,6 +380,7 @@ Response: ```json { "id": 46, + "iid": 11, "project_id": 1, "status": "canceled", "ref": "main", diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md index 4356d3582b3..1070fabf526 100644 --- a/doc/user/project/releases/index.md +++ b/doc/user/project/releases/index.md @@ -612,6 +612,18 @@ These metrics include: - Total number of releases in the group - Percentage of projects in the group that have at least one release +## Working example project + +The Guided Exploration project [Utterly Automated Software and Artifact Versioning with GitVersion](https://gitlab.com/guided-explorations/devops-patterns/utterly-automated-versioning) demonstrates: + +- Using GitLab releases. +- Using the GitLab `release-cli`. +- Creating a generic package. +- Linking the package to the release. +- Using a tool called [GitVersion](https://gitversion.net/) to automatically determine and increment versions for complex repositories. + +You can copy the example project to your own group or instance for testing. More details on what other GitLab CI patterns are demonstrated are available at the project page. + ## Troubleshooting ### Getting `403 Forbidden` or `Something went wrong while creating a new release` errors when creating, updating or deleting releases and their assets diff --git a/doc/user/project/repository/repository_mirroring.md b/doc/user/project/repository/repository_mirroring.md index 71bece03a33..8d259983bd8 100644 --- a/doc/user/project/repository/repository_mirroring.md +++ b/doc/user/project/repository/repository_mirroring.md @@ -92,19 +92,18 @@ You can also create and modify project push mirrors through the > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/208828) in GitLab 13.0. -By default, if any ref on the remote mirror has diverged from the local -repository, the *entire push* fails, and no updates occur. +By default, if any ref (branch or tag) on the remote mirror has diverged from the local repository, the local differences are forced to the remote. -For example, if a repository has `main`, `develop`, and `stable` branches that +For example, if a repository has `main` and `develop` branches that have been mirrored to a remote, and then a new commit is added to `develop` on -the mirror, the next push attempt fails, leaving `main` and `stable` -out-of-date despite not having diverged. No change on any branch can be mirrored -until the divergence is resolved. +the remote mirror. The next push updates all of the references on the remote mirror to match +the local repository, and the new commit added to the remote `develop` branch is lost. With the **Keep divergent refs** option enabled, the `develop` branch is -skipped, allowing `main` and `stable` to be updated. The mirror status -reflects that `develop` has diverged and was skipped, and be marked as a failed -update. +skipped, causing only `main` to be updated. The mirror status +reflects that `develop` has diverged and was skipped, and be marked as a +failed update. Refs that exist in the mirror repository but not in the local +repository are left untouched. NOTE: After the mirror is created, this option can only be modified via the [API](../../../api/remote_mirrors.md). diff --git a/lib/feature.rb b/lib/feature.rb index 26dbdd53968..f8d34e9c386 100644 --- a/lib/feature.rb +++ b/lib/feature.rb @@ -56,7 +56,7 @@ class Feature # use `default_enabled: true` to default the flag to being `enabled` # unless set explicitly. The default is `disabled` - # TODO: remove the `default_enabled:` and read it from the `defintion_yaml` + # TODO: remove the `default_enabled:` and read it from the `definition_yaml` # check: https://gitlab.com/gitlab-org/gitlab/-/issues/30228 def enabled?(key, thing = nil, type: :development, default_enabled: false) if check_feature_flags_definition? diff --git a/lib/gitlab/markdown_cache.rb b/lib/gitlab/markdown_cache.rb index d0702190ac0..db39904ea23 100644 --- a/lib/gitlab/markdown_cache.rb +++ b/lib/gitlab/markdown_cache.rb @@ -2,10 +2,14 @@ module Gitlab module MarkdownCache - # Increment this number every time the renderer changes its output. + # Increment this number to invalidate cached HTML from Markdown documents. + # Even when reverting an MR, we should increment this because we only + # persist the cache when the new version is higher. + # # Changing this value puts strain on the database, as every row with - # cached markdown needs to be updated. As a result, this line should - # not be changed. + # cached markdown needs to be updated. As a result, avoid changing + # this if the change to the renderer output is a new feature or a + # minor bug fix. # See: https://gitlab.com/gitlab-org/gitlab/-/issues/330313 CACHE_COMMONMARK_VERSION = 28 CACHE_COMMONMARK_VERSION_START = 10 diff --git a/lib/gitlab/markdown_cache/active_record/extension.rb b/lib/gitlab/markdown_cache/active_record/extension.rb index af94884f1a7..f73631c9599 100644 --- a/lib/gitlab/markdown_cache/active_record/extension.rb +++ b/lib/gitlab/markdown_cache/active_record/extension.rb @@ -39,6 +39,7 @@ module Gitlab def save_markdown(updates) return unless persisted? && Gitlab::Database.read_write? + return if cached_markdown_version < cached_markdown_version_in_database update_columns(updates) end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 039ed280f25..c4fb5f61c54 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -676,7 +676,7 @@ msgstr "" msgid "%{label_for_message} unavailable" msgstr "" -msgid "%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} is a free, automated, and open certificate authority (CA), that give digital certificates in order to enable HTTPS (SSL/TLS) for websites." +msgid "%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} is a free, automated, and open certificate authority (CA) that issues digital certificates to enable HTTPS (SSL/TLS) for sites." msgstr "" msgid "%{level_name} is not allowed in a %{group_level_name} group." @@ -1191,9 +1191,6 @@ msgstr "" msgid "0 bytes" msgstr "" -msgid "0 for unlimited" -msgstr "" - msgid "0 for unlimited, only effective with remote storage enabled." msgstr "" @@ -1402,9 +1399,6 @@ msgstr "" msgid "A Let's Encrypt SSL certificate can not be obtained until your domain is verified." msgstr "" -msgid "A Let's Encrypt account will be configured for this GitLab installation using your email address. You will receive emails to warn of expiring certificates." -msgstr "" - msgid "A Metrics Dashboard menu item appears in the Monitoring section of the Admin Area." msgstr "" @@ -1726,9 +1720,6 @@ msgstr "" msgid "Access to '%{classification_label}' not allowed" msgstr "" -msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance." -msgstr "" - msgid "AccessDropdown|Deploy Keys" msgstr "" @@ -2365,27 +2356,45 @@ msgstr "" msgid "AdminProjects|Delete Project %{projectName}?" msgstr "" +msgid "AdminSettings|A Let's Encrypt account will be configured for this GitLab instance using this email address. You will receive emails to warn of expiring certificates. %{link_start}Learn more.%{link_end}" +msgstr "" + msgid "AdminSettings|All new projects can use the instance's shared runners by default." msgstr "" msgid "AdminSettings|Auto DevOps domain" msgstr "" +msgid "AdminSettings|Configure Let's Encrypt" +msgstr "" + msgid "AdminSettings|Disable feed token" msgstr "" +msgid "AdminSettings|Disable public access to Pages sites" +msgstr "" + +msgid "AdminSettings|Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled. %{link_start}Learn more.%{link_end}" +msgstr "" + msgid "AdminSettings|Enable shared runners for new projects" msgstr "" msgid "AdminSettings|Feed token" msgstr "" +msgid "AdminSettings|I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end} (PDF)." +msgstr "" + msgid "AdminSettings|If not specified at the group or instance level, the default is %{default_initial_branch_name}. Does not affect existing repositories." msgstr "" msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines" msgstr "" +msgid "AdminSettings|Let's Encrypt email" +msgstr "" + msgid "AdminSettings|Maximum duration of a session for Git operations when 2FA is enabled." msgstr "" @@ -2398,6 +2407,9 @@ msgstr "" msgid "AdminSettings|Protect CI/CD variables by default" msgstr "" +msgid "AdminSettings|Require users to prove ownership of custom domains" +msgstr "" + msgid "AdminSettings|Required pipeline configuration" msgstr "" @@ -2407,12 +2419,21 @@ msgstr "" msgid "AdminSettings|Select a group to use as the source for instance-level project templates." msgstr "" +msgid "AdminSettings|Select to disable public access for Pages sites, which requires users to sign in for access to the Pages sites in your instance. %{link_start}Learn more.%{link_end}" +msgstr "" + msgid "AdminSettings|Session duration for Git operations when 2FA is enabled (minutes)" msgstr "" msgid "AdminSettings|Set a CI/CD template as the required pipeline configuration for all projects in the instance. Project CI/CD configuration merges into the required pipeline configuration when the pipeline runs. %{link_start}What is a required pipeline configuration?%{link_end}" msgstr "" +msgid "AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}" +msgstr "" + +msgid "AdminSettings|Size and domain settings for Pages static sites." +msgstr "" + msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects." msgstr "" @@ -5832,9 +5853,6 @@ msgstr "" msgid "By default, all projects and groups will use the global notifications setting." msgstr "" -msgid "By default, if any ref (branch, tag, or commit) on the remote mirror has diverged from the local repository, the entire push will fail, and nothing will be updated. Choose this option to override this behavior. After the mirror is created, this can only be modified via the API." -msgstr "" - msgid "ByAuthor|by" msgstr "" @@ -8395,9 +8413,6 @@ msgstr "" msgid "Configure Integrations" msgstr "" -msgid "Configure Let's Encrypt" -msgstr "" - msgid "Configure Prometheus" msgstr "" @@ -11559,9 +11574,6 @@ msgstr "" msgid "Disable group runners" msgstr "" -msgid "Disable public access to Pages sites" -msgstr "" - msgid "Disable two-factor authentication" msgstr "" @@ -11705,6 +11717,9 @@ msgstr "" msgid "Do not display offers from third parties" msgstr "" +msgid "Do not force push over diverged refs. After the mirror is created, this setting can only be modified using the API. %{mirroring_docs_link_start}Learn more about this option%{link_closing_tag} and %{mirroring_api_docs_link_start}the API.%{link_closing_tag}" +msgstr "" + msgid "Do you want to remove this deploy key?" msgstr "" @@ -11732,9 +11747,6 @@ msgstr "" msgid "Domain cannot be deleted while associated to one or more clusters." msgstr "" -msgid "Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled" -msgstr "" - msgid "Domain was successfully created." msgstr "" @@ -16455,9 +16467,6 @@ msgstr "" msgid "I forgot my password" msgstr "" -msgid "I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end} (PDF)" -msgstr "" - msgid "I want to explore GitLab to see if it’s worth switching to" msgstr "" @@ -28074,9 +28083,6 @@ msgstr "" msgid "Require user password for approvals." msgstr "" -msgid "Require users to prove ownership of custom domains" -msgstr "" - msgid "Required approvals (%{approvals_given} given)" msgstr "" @@ -30652,9 +30658,6 @@ msgstr "" msgid "Size" msgstr "" -msgid "Size and domain settings for static websites" -msgstr "" - msgid "Size limit per repository (MB)" msgstr "" diff --git a/package.json b/package.json index 3638b5b1091..518beee7ad0 100644 --- a/package.json +++ b/package.json @@ -57,9 +57,9 @@ "@babel/preset-env": "^7.10.1", "@gitlab/at.js": "1.5.7", "@gitlab/favicon-overlay": "2.0.0", - "@gitlab/svgs": "1.205.0", + "@gitlab/svgs": "1.207.0", "@gitlab/tributejs": "1.0.0", - "@gitlab/ui": "31.6.0", + "@gitlab/ui": "31.6.1", "@gitlab/visual-review-tools": "1.6.1", "@rails/actioncable": "6.1.3-2", "@rails/ujs": "6.1.3-2", diff --git a/scripts/frontend/startup_css/constants.js b/scripts/frontend/startup_css/constants.js index 5bd7c073e90..8f183e63659 100644 --- a/scripts/frontend/startup_css/constants.js +++ b/scripts/frontend/startup_css/constants.js @@ -49,7 +49,6 @@ const createMainOutput = ({ outFile, cssKeys, type }) => ({ outFile, htmlPaths: [ path.join(FIXTURES_ROOT, `startup_css/project-${type}.html`), - path.join(FIXTURES_ROOT, `startup_css/project-${type}-legacy-sidebar.html`), path.join(FIXTURES_ROOT, `startup_css/project-${type}-signed-out.html`), ], cssKeys, diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index a697baa1512..902c75efcc7 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -634,7 +634,7 @@ RSpec.describe 'Admin updates settings' do it "change Pages Let's Encrypt settings" do visit preferences_admin_application_settings_path page.within('.as-pages') do - fill_in 'Email', with: 'my@test.example.com' + fill_in "Let's Encrypt email", with: 'my@test.example.com' check "I have read and agree to the Let's Encrypt Terms of Service" click_button 'Save changes' end diff --git a/spec/frontend/fixtures/startup_css.rb b/spec/frontend/fixtures/startup_css.rb index 53da7d7cb85..be2ead756cf 100644 --- a/spec/frontend/fixtures/startup_css.rb +++ b/spec/frontend/fixtures/startup_css.rb @@ -10,7 +10,6 @@ RSpec.describe 'Startup CSS fixtures', type: :controller do render_views before(:all) do - stub_feature_flags(sidebar_refactor: true) clean_frontend_fixtures('startup_css/') end @@ -31,17 +30,6 @@ RSpec.describe 'Startup CSS fixtures', type: :controller do expect(response).to be_successful end - it "startup_css/project-#{type}-legacy-sidebar.html" do - stub_feature_flags(sidebar_refactor: false) - - get :show, params: { - namespace_id: project.namespace.to_param, - id: project - } - - expect(response).to be_successful - end - it "startup_css/project-#{type}-signed-out.html" do sign_out(user) diff --git a/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb b/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb index 60792a6bf65..6494cdfe522 100644 --- a/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb +++ b/spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb @@ -216,4 +216,16 @@ RSpec.describe Gitlab::MarkdownCache::ActiveRecord::Extension do end end end + + context 'when persisted cache is newer than current version' do + before do + thing.update_column(:cached_markdown_version, thing.cached_markdown_version + 1) + end + + it 'does not save the generated HTML' do + expect(thing).not_to receive(:update_columns) + + thing.refresh_markdown_cache! + end + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 0aad1257eea..f16277c3ff6 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -4039,6 +4039,14 @@ RSpec.describe User do ] end end + + context 'when the user is not saved' do + let(:user) { build(:user) } + + it 'returns empty when there are no groups or ancestor groups for the user' do + is_expected.to eq([]) + end + end end describe '#refresh_authorized_projects', :clean_gitlab_redis_shared_state do @@ -4300,6 +4308,14 @@ RSpec.describe User do expect(user.two_factor_grace_period).to be 48 end end + + context 'when the user is not saved' do + let(:user) { build(:user) } + + it 'does not raise an ActiveRecord::StatementInvalid statement exception' do + expect { user.update_two_factor_requirement }.not_to raise_error + end + end end describe '#source_groups_of_two_factor_authentication_requirement' do diff --git a/spec/serializers/ci/pipeline_entity_spec.rb b/spec/serializers/ci/pipeline_entity_spec.rb index 054406e4e65..f79bbd91a0a 100644 --- a/spec/serializers/ci/pipeline_entity_spec.rb +++ b/spec/serializers/ci/pipeline_entity_spec.rb @@ -18,7 +18,7 @@ RSpec.describe Ci::PipelineEntity do let(:pipeline) { create(:ci_empty_pipeline) } it 'contains required fields' do - expect(subject).to include :id, :user, :path, :coverage, :source + expect(subject).to include :id, :iid, :user, :path, :coverage, :source expect(subject).to include :ref, :commit expect(subject).to include :updated_at, :created_at end diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb index 5898504b463..fd858fa9550 100644 --- a/spec/services/projects/update_pages_service_spec.rb +++ b/spec/services/projects/update_pages_service_spec.rb @@ -158,6 +158,21 @@ RSpec.describe Projects::UpdatePagesService do expect(execute).not_to eq(:success) end + it 'limits pages file count' do + create(:plan_limits, :default_plan, pages_file_entries: 2) + + expect(execute).not_to eq(:success) + + expect(GenericCommitStatus.last.description).to eq("pages site contains 3 file entries, while limit is set to 2") + end + + it 'does not limit pages file count if feature is disabled' do + stub_feature_flags(pages_limit_entries_count: false) + create(:plan_limits, :default_plan, pages_file_entries: 2) + + expect(execute).to eq(:success) + end + it 'removes pages after destroy' do expect(PagesWorker).to receive(:perform_in) expect(project.pages_deployed?).to be_falsey @@ -339,9 +354,15 @@ RSpec.describe Projects::UpdatePagesService do create(:ci_job_artifact, :archive, file: file, job: build) create(:ci_job_artifact, :metadata, file: metafile, job: build) - allow(build).to receive(:artifacts_metadata_entry) + allow(build).to receive(:artifacts_metadata_entry).with('public/', recursive: true) .and_return(metadata) allow(metadata).to receive(:total_size).and_return(100) + + # to pass entries count check + root_metadata = double('root metadata') + allow(build).to receive(:artifacts_metadata_entry).with('', recursive: true) + .and_return(root_metadata) + allow(root_metadata).to receive_message_chain(:entries, :count).and_return(10) end it 'raises an error' do diff --git a/spec/support/shared_examples/features/packages_shared_examples.rb b/spec/support/shared_examples/features/packages_shared_examples.rb index 9e88db2e1c0..361e9590999 100644 --- a/spec/support/shared_examples/features/packages_shared_examples.rb +++ b/spec/support/shared_examples/features/packages_shared_examples.rb @@ -100,7 +100,7 @@ def click_sort_option(option, ascending) # Reset the sort direction click_button 'Sort direction' if page.has_selector?('svg[aria-label="Sorting Direction: Ascending"]', wait: 0) - find('button.dropdown-menu-toggle').click + find('button.gl-dropdown-toggle').click page.within('.dropdown-menu') do click_button option diff --git a/yarn.lock b/yarn.lock index 37b8a1e6c2a..3ad7f4a5381 100644 --- a/yarn.lock +++ b/yarn.lock @@ -898,20 +898,20 @@ stylelint-declaration-strict-value "1.7.7" stylelint-scss "3.18.0" -"@gitlab/svgs@1.205.0": - version "1.205.0" - resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.205.0.tgz#f8c084b6ef6a5f7eec676710f2c873992ebc2c83" - integrity sha512-cO9uqVCKE8O5ABlCd0m4W9EQrKwQyc536sF9KjwoLAxbqel8mlIo0C3HVIb367NuOpS2IWZdjN7GlNhulwffVA== +"@gitlab/svgs@1.207.0": + version "1.207.0" + resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.207.0.tgz#39a1ff30b79a7c1134bcdc086a96e01988b89034" + integrity sha512-1JTuocHt1xk3fAP/C7xV79EJNtHmnoIAs+39eY3aidrgTo3hK8XkyANNBAmVooY0RdfUhK3juHfmj7i/C1ps0g== "@gitlab/tributejs@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8" integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw== -"@gitlab/ui@31.6.0": - version "31.6.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-31.6.0.tgz#70aeb2b497aea15ea0a0a223b7332bc608587ff1" - integrity sha512-HABk7zwF7h5jaNaRiGKnWEkuQiPIm/bDRUzAtV3d/E/OgIzAU9S/fX3SHOrbj44g4Kq3mXifa4omMhEORx+mQg== +"@gitlab/ui@31.6.1": + version "31.6.1" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-31.6.1.tgz#32acb2c9b6ded53077d703c071774c262db4c48b" + integrity sha512-x3851iL9N4qIIKqjVquFPuFk4IcrJwMVGCe2iVrCDfOckbHSnvKrR1QYO+wgx/OpLt818hD7BcMXd4R+p1Cz4Q== dependencies: "@babel/standalone" "^7.0.0" bootstrap-vue "2.18.1" |