diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-07 12:10:27 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-07 12:10:27 +0300 |
commit | e8a31d8dc2afd673ca50d74d26edab0a0fec83ca (patch) | |
tree | 82c044733ca8d491dc2311231febdb966280950d | |
parent | a158bebe03b366b6463af181b9ee6f6c2b3850a3 (diff) |
Add latest changes from gitlab-org/gitlab@master
39 files changed, 420 insertions, 59 deletions
diff --git a/app/assets/javascripts/boards/components/board_content_sidebar.vue b/app/assets/javascripts/boards/components/board_content_sidebar.vue index 5a41a01e167..7ce9492f79b 100644 --- a/app/assets/javascripts/boards/components/board_content_sidebar.vue +++ b/app/assets/javascripts/boards/components/board_content_sidebar.vue @@ -11,7 +11,6 @@ import { contentTop } from '~/lib/utils/common_utils'; import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue'; import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue'; import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue'; -import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; export default { headerHeight: `${contentTop()}px`, @@ -32,7 +31,17 @@ export default { SidebarIterationWidget: () => import('ee_component/sidebar/components/sidebar_iteration_widget.vue'), }, - mixins: [glFeatureFlagsMixin()], + inject: { + epicFeatureAvailable: { + default: false, + }, + iterationFeatureAvailable: { + default: false, + }, + weightFeatureAvailable: { + default: false, + }, + }, computed: { ...mapGetters([ 'isSidebarOpen', @@ -77,10 +86,11 @@ export default { class="assignee" @assignees-updated="setAssignees" /> - <board-sidebar-epic-select class="epic" /> + <board-sidebar-epic-select v-if="epicFeatureAvailable" class="epic" /> <div> <board-sidebar-milestone-select /> <sidebar-iteration-widget + v-if="iterationFeatureAvailable" :iid="activeBoardItem.iid" :workspace-path="projectPathForActiveIssue" :iterations-workspace-path="groupPathForActiveIssue" @@ -91,7 +101,7 @@ export default { <board-sidebar-time-tracker class="swimlanes-sidebar-time-tracker" /> <board-sidebar-due-date /> <board-sidebar-labels-select class="labels" /> - <board-sidebar-weight-input v-if="glFeatures.issueWeights" class="weight" /> + <board-sidebar-weight-input v-if="weightFeatureAvailable" class="weight" /> <sidebar-confidentiality-widget :iid="activeBoardItem.iid" :full-path="fullPath" diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index 84beaebfb4b..97006cea3f1 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -101,6 +101,8 @@ export default () => { labelsManagePath: $boardApp.dataset.labelsManagePath, labelsFilterBasePath: $boardApp.dataset.labelsFilterBasePath, timeTrackingLimitToHours: parseBoolean($boardApp.dataset.timeTrackingLimitToHours), + epicFeatureAvailable: parseBoolean($boardApp.dataset.epicFeatureAvailable), + iterationFeatureAvailable: parseBoolean($boardApp.dataset.iterationFeatureAvailable), weightFeatureAvailable: parseBoolean($boardApp.dataset.weightFeatureAvailable), boardWeight: $boardApp.dataset.boardWeight ? parseInt($boardApp.dataset.boardWeight, 10) diff --git a/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts.vue b/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts.vue index b7b33701ab1..1c4413bef71 100644 --- a/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts.vue +++ b/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts.vue @@ -301,7 +301,7 @@ export default { <statistics-list v-else :counts="formattedCounts" /> </div> <div v-if="!loading" class="col-md-6"> - <strong>{{ __('Duration for the last 30 commits') }}</strong> + <strong>{{ __('Pipeline durations for the last 30 commits') }}</strong> <gl-column-chart :height="$options.chartContainerHeight" :option="$options.timesChartOptions" diff --git a/app/assets/javascripts/static_site_editor/constants.js b/app/assets/javascripts/static_site_editor/constants.js index 5fb20b00705..b08bf26e1dc 100644 --- a/app/assets/javascripts/static_site_editor/constants.js +++ b/app/assets/javascripts/static_site_editor/constants.js @@ -1,7 +1,6 @@ import { s__, __ } from '~/locale'; export const BRANCH_SUFFIX_COUNT = 8; -export const DEFAULT_TARGET_BRANCH = 'master'; export const ISSUABLE_TYPE = 'merge_request'; export const SUBMIT_CHANGES_BRANCH_ERROR = s__('StaticSiteEditor|Branch could not be created.'); diff --git a/app/assets/javascripts/static_site_editor/graphql/resolvers/submit_content_changes.js b/app/assets/javascripts/static_site_editor/graphql/resolvers/submit_content_changes.js index 0b74c99b319..e9f1828bff8 100644 --- a/app/assets/javascripts/static_site_editor/graphql/resolvers/submit_content_changes.js +++ b/app/assets/javascripts/static_site_editor/graphql/resolvers/submit_content_changes.js @@ -9,6 +9,7 @@ const submitContentChangesResolver = ( project: projectId, username, sourcePath, + targetBranch, content, images, mergeRequestMeta, @@ -21,6 +22,7 @@ const submitContentChangesResolver = ( projectId, username, sourcePath, + targetBranch, content, images, mergeRequestMeta, diff --git a/app/assets/javascripts/static_site_editor/pages/home.vue b/app/assets/javascripts/static_site_editor/pages/home.vue index 22f80ead74b..49a2ca03ace 100644 --- a/app/assets/javascripts/static_site_editor/pages/home.vue +++ b/app/assets/javascripts/static_site_editor/pages/home.vue @@ -111,6 +111,7 @@ export default { project: this.appData.project, username: this.appData.username, sourcePath: this.appData.sourcePath, + targetBranch: this.appData.branch, content: this.content, formattedMarkdown: this.formattedMarkdown, images: this.images, diff --git a/app/assets/javascripts/static_site_editor/services/generate_branch_name.js b/app/assets/javascripts/static_site_editor/services/generate_branch_name.js index f45ad616332..cbf03a41ce2 100644 --- a/app/assets/javascripts/static_site_editor/services/generate_branch_name.js +++ b/app/assets/javascripts/static_site_editor/services/generate_branch_name.js @@ -1,8 +1,8 @@ -import { BRANCH_SUFFIX_COUNT, DEFAULT_TARGET_BRANCH } from '../constants'; +import { BRANCH_SUFFIX_COUNT } from '../constants'; const generateBranchSuffix = () => `${Date.now()}`.substr(BRANCH_SUFFIX_COUNT); -const generateBranchName = (username, targetBranch = DEFAULT_TARGET_BRANCH) => +const generateBranchName = (username, targetBranch) => `${username}-${targetBranch}-patch-${generateBranchSuffix()}`; export default generateBranchName; diff --git a/app/assets/javascripts/static_site_editor/services/submit_content_changes.js b/app/assets/javascripts/static_site_editor/services/submit_content_changes.js index 6391cfd6cc2..ecb7f60a421 100644 --- a/app/assets/javascripts/static_site_editor/services/submit_content_changes.js +++ b/app/assets/javascripts/static_site_editor/services/submit_content_changes.js @@ -4,7 +4,6 @@ import generateBranchName from '~/static_site_editor/services/generate_branch_na import Tracking from '~/tracking'; import { - DEFAULT_TARGET_BRANCH, SUBMIT_CHANGES_BRANCH_ERROR, SUBMIT_CHANGES_COMMIT_ERROR, SUBMIT_CHANGES_MERGE_REQUEST_ERROR, @@ -16,9 +15,9 @@ import { DEFAULT_FORMATTING_CHANGES_COMMIT_DESCRIPTION, } from '../constants'; -const createBranch = (projectId, branch) => +const createBranch = (projectId, branch, targetBranch) => Api.createBranch(projectId, { - ref: DEFAULT_TARGET_BRANCH, + ref: targetBranch, branch, }).catch(() => { throw new Error(SUBMIT_CHANGES_BRANCH_ERROR); @@ -73,13 +72,7 @@ const commit = (projectId, message, branch, actions) => { }); }; -const createMergeRequest = ( - projectId, - title, - description, - sourceBranch, - targetBranch = DEFAULT_TARGET_BRANCH, -) => { +const createMergeRequest = (projectId, title, description, sourceBranch, targetBranch) => { Tracking.event(document.body.dataset.page, TRACKING_ACTION_CREATE_MERGE_REQUEST); Api.trackRedisCounterEvent(USAGE_PING_TRACKING_ACTION_CREATE_MERGE_REQUEST); @@ -100,16 +93,17 @@ const submitContentChanges = ({ username, projectId, sourcePath, + targetBranch, content, images, mergeRequestMeta, formattedMarkdown, }) => { - const branch = generateBranchName(username); + const branch = generateBranchName(username, targetBranch); const { title: mergeRequestTitle, description: mergeRequestDescription } = mergeRequestMeta; const meta = {}; - return createBranch(projectId, branch) + return createBranch(projectId, branch, targetBranch) .then(({ data: { web_url: url } }) => { const message = `${DEFAULT_FORMATTING_CHANGES_COMMIT_MESSAGE}\n\n${DEFAULT_FORMATTING_CHANGES_COMMIT_DESCRIPTION}`; @@ -133,7 +127,13 @@ const submitContentChanges = ({ .then(({ data: { short_id: label, web_url: url } }) => { Object.assign(meta, { commit: { label, url } }); - return createMergeRequest(projectId, mergeRequestTitle, mergeRequestDescription, branch); + return createMergeRequest( + projectId, + mergeRequestTitle, + mergeRequestDescription, + branch, + targetBranch, + ); }) .then(({ data: { iid: label, web_url: url } }) => { Object.assign(meta, { mergeRequest: { label: label.toString(), url } }); diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 8a53a9b9555..56ccb7090f4 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -22,6 +22,7 @@ class ApplicationController < ActionController::Base include Gitlab::Logging::CloudflareHelper include Gitlab::Utils::StrongMemoize include ::Gitlab::WithFeatureCategory + include FlocOptOut before_action :authenticate_user!, except: [:route_not_found] before_action :enforce_terms!, if: :should_enforce_terms? diff --git a/app/controllers/concerns/floc_opt_out.rb b/app/controllers/concerns/floc_opt_out.rb new file mode 100644 index 00000000000..3039af02bbb --- /dev/null +++ b/app/controllers/concerns/floc_opt_out.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module FlocOptOut + extend ActiveSupport::Concern + + included do + after_action :set_floc_opt_out_header, unless: :floc_enabled? + end + + def floc_enabled? + Gitlab::CurrentSettings.floc_enabled + end + + def set_floc_opt_out_header + response.headers['Permissions-Policy'] = 'interest-cohort=()' + end +end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 051f7cf5bb8..90f5ab5f647 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -233,6 +233,7 @@ module ApplicationSettingsHelper :external_pipeline_validation_service_token, :external_pipeline_validation_service_url, :first_day_of_week, + :floc_enabled, :force_pages_access_control, :gitaly_timeout_default, :gitaly_timeout_medium, diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 2d4b2ce135e..429f0e58e45 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -504,6 +504,9 @@ class ApplicationSetting < ApplicationRecord validates :whats_new_variant, inclusion: { in: ApplicationSetting.whats_new_variants.keys } + validates :floc_enabled, + inclusion: { in: [true, false], message: _('must be a boolean value') } + attr_encrypted :asset_proxy_secret_key, mode: :per_attribute_iv, key: Settings.attr_encrypted_db_key_base_truncated, diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index a38804c7367..5ff1c653f9e 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -77,6 +77,7 @@ module ApplicationSettingImplementation external_pipeline_validation_service_token: nil, external_pipeline_validation_service_url: nil, first_day_of_week: 0, + floc_enabled: false, gitaly_timeout_default: 55, gitaly_timeout_fast: 10, gitaly_timeout_medium: 30, diff --git a/app/views/admin/application_settings/_floc.html.haml b/app/views/admin/application_settings/_floc.html.haml new file mode 100644 index 00000000000..398064f9730 --- /dev/null +++ b/app/views/admin/application_settings/_floc.html.haml @@ -0,0 +1,22 @@ +- expanded = integration_expanded?('floc_') + +%section.settings.no-animate#js-floc-settings{ class: ('expanded' if expanded) } + .settings-header + %h4 + = s_('FloC|Federated Learning of Cohorts') + %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' } + = expanded ? _('Collapse') : _('Expand') + %p + = s_('FloC|Configure whether you want to participate in FloC.').html_safe + = link_to sprite_icon('question-o'), 'https://github.com/WICG/floc', target: '_blank', class: 'has-tooltip', title: _('More information') + + .settings-content + = form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-floc-settings'), html: { class: 'fieldset-form', id: 'floc-settings' } do |f| + = form_errors(@application_setting) + + %fieldset + .form-group + .form-check + = f.check_box :floc_enabled, class: 'form-check-input' + = f.label :floc_enabled, s_('FloC|Enable FloC (Federated Learning of Cohorts)'), class: 'form-check-label' + = f.submit s_('Save changes'), class: 'gl-button btn btn-confirm' diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml index 86226a9de2f..217225e6186 100644 --- a/app/views/admin/application_settings/general.html.haml +++ b/app/views/admin/application_settings/general.html.haml @@ -112,3 +112,4 @@ = render 'admin/application_settings/third_party_offers' = render 'admin/application_settings/snowplow' = render 'admin/application_settings/eks' += render 'admin/application_settings/floc' diff --git a/changelogs/unreleased/32107-delete-package-file-api.yml b/changelogs/unreleased/32107-delete-package-file-api.yml new file mode 100644 index 00000000000..0aeffe42b77 --- /dev/null +++ b/changelogs/unreleased/32107-delete-package-file-api.yml @@ -0,0 +1,5 @@ +--- +title: Add API endpoint for deleting a package file +merge_request: 60970 +author: +type: added diff --git a/changelogs/unreleased/leipert-floc-opt-out-327904.yml b/changelogs/unreleased/leipert-floc-opt-out-327904.yml new file mode 100644 index 00000000000..93bff73e640 --- /dev/null +++ b/changelogs/unreleased/leipert-floc-opt-out-327904.yml @@ -0,0 +1,5 @@ +--- +title: Application setting for FloC participation (disabled by default) +merge_request: 60933 +author: +type: added diff --git a/config/feature_flags/development/track_epic_boards_activity.yml b/config/feature_flags/development/track_epic_boards_activity.yml new file mode 100644 index 00000000000..6461a9e826c --- /dev/null +++ b/config/feature_flags/development/track_epic_boards_activity.yml @@ -0,0 +1,8 @@ +--- +name: track_epic_boards_activity +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60357 +rollout_issue_url: +milestone: '13.12' +type: development +group: group::product planning +default_enabled: true diff --git a/db/migrate/20210504135823_add_floc_application_settings.rb b/db/migrate/20210504135823_add_floc_application_settings.rb new file mode 100644 index 00000000000..a5e3aad6b8c --- /dev/null +++ b/db/migrate/20210504135823_add_floc_application_settings.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddFlocApplicationSettings < ActiveRecord::Migration[6.0] + def change + add_column :application_settings, :floc_enabled, :boolean, default: false, null: false + end +end diff --git a/db/schema_migrations/20210504135823 b/db/schema_migrations/20210504135823 new file mode 100644 index 00000000000..24c5fd50087 --- /dev/null +++ b/db/schema_migrations/20210504135823 @@ -0,0 +1 @@ +9d1254393da80e0b1e387fba493f83f8775f0340f23c648e638a9983f965f5c9
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index ce42f7362ca..976ac394aae 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -9513,6 +9513,7 @@ CREATE TABLE application_settings ( whats_new_variant smallint DEFAULT 0, encrypted_spam_check_api_key bytea, encrypted_spam_check_api_key_iv bytea, + floc_enabled boolean DEFAULT false NOT NULL, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)), CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)), diff --git a/doc/api/packages.md b/doc/api/packages.md index 7ad99475515..c257105f72e 100644 --- a/doc/api/packages.md +++ b/doc/api/packages.md @@ -352,3 +352,33 @@ Can return the following status codes: - `204 No Content`, if the package was deleted successfully. - `404 Not Found`, if the package was not found. + +## Delete a package file + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32107) in GitLab 13.12. + +WARNING: +Deleting a package file may corrupt your package making it unusable or unpullable from your package +manager client. When deleting a package file, be sure that you understand what you're doing. + +Delete a package file: + +```plaintext +DELETE /projects/:id/packages/:package_id/package_files/:package_file_id +``` + +| Attribute | Type | Required | Description | +| ----------------- | -------------- | -------- | ----------- | +| `id` | integer/string | yes | ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). | +| `package_id` | integer | yes | ID of a package. | +| `package_file_id` | integer | yes | ID of a package file. | + +```shell +curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/packages/:package_id/package_files/:package_file_id" +``` + +Can return the following status codes: + +- `204 No Content`: The package was deleted successfully. +- `403 Forbidden`: The user does not have permission to delete the file. +- `404 Not Found`: The package or package file was not found. diff --git a/doc/api/settings.md b/doc/api/settings.md index 38251550ae4..0f0a36c0b5d 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -88,6 +88,7 @@ Example response: "rate_limiting_response_text": null, "keep_latest_artifact": true, "admin_mode": false, + "floc_enabled": false, "external_pipeline_validation_service_timeout": null, "external_pipeline_validation_service_token": null, "external_pipeline_validation_service_url": null diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md index 80816bf583a..0ec481511fa 100644 --- a/doc/development/usage_ping/dictionary.md +++ b/doc/development/usage_ping/dictionary.md @@ -10234,6 +10234,78 @@ Status: `data_available` Tiers: `free`, `premium`, `ultimate` +### `redis_hll_counters.epic_boards_usage.g_project_management_users_creating_epic_boards_monthly` + +Count of MAU creating epic boards + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210428072511_g_project_management_users_creating_epic_boards_monthly.yml) + +Group: `group::product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + +### `redis_hll_counters.epic_boards_usage.g_project_management_users_creating_epic_boards_weekly` + +Count of WAU creating epic boards + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210428072508_g_project_management_users_creating_epic_boards_weekly.yml) + +Group: `group::product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + +### `redis_hll_counters.epic_boards_usage.g_project_management_users_updating_epic_board_names_monthly` + +Count of MAU updating epic board names + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210428073607_g_project_management_users_updating_epic_board_names_monthly.yml) + +Group: `group::product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + +### `redis_hll_counters.epic_boards_usage.g_project_management_users_updating_epic_board_names_weekly` + +Count of WAU updating epic board names + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210428073604_g_project_management_users_updating_epic_board_names_weekly.yml) + +Group: `group::product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + +### `redis_hll_counters.epic_boards_usage.g_project_management_users_viewing_epic_boards_monthly` + +Count of MAU viewing epic boards + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210428073329_g_project_management_users_viewing_epic_boards_monthly.yml) + +Group: `group::product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + +### `redis_hll_counters.epic_boards_usage.g_project_management_users_viewing_epic_boards_weekly` + +Count of WAU viewing epic boards + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210428073327_g_project_management_users_viewing_epic_boards_weekly.yml) + +Group: `group::product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + ### `redis_hll_counters.epics_usage.epics_usage_total_unique_counts_monthly` Total monthly users count for epics_usage diff --git a/doc/user/analytics/img/pipelines_duration_chart.png b/doc/user/analytics/img/pipelines_duration_chart.png Binary files differindex 12ec262dadb..17ab7173557 100644 --- a/doc/user/analytics/img/pipelines_duration_chart.png +++ b/doc/user/analytics/img/pipelines_duration_chart.png diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md index 94bcc144167..b01a0c4c327 100644 --- a/doc/user/group/saml_sso/index.md +++ b/doc/user/group/saml_sso/index.md @@ -92,11 +92,11 @@ Please note that the certificate [fingerprint algorithm](../../../integration/sa ### SSO enforcement -- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5291) in GitLab 11.8. -- [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/9255) in GitLab 11.11 with ongoing enforcement in the GitLab UI. -- [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/292811) in GitLab 13.8, with an updated timeout experience. -- [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/211962) in GitLab 13.8 with allowing group owners to not go through SSO. -- [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/9152) in GitLab 13.11 with enforcing open SSO session to use Git if this setting is switched on. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5291) in GitLab 11.8. +> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/9255) in GitLab 11.11 with ongoing enforcement in the GitLab UI. +> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/292811) in GitLab 13.8, with an updated timeout experience. +> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/211962) in GitLab 13.8 with allowing group owners to not go through SSO. +> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/9152) in GitLab 13.11 with enforcing open SSO session to use Git if this setting is switched on. With this option enabled, users (except owners) must go through your group's GitLab single sign-on URL if they wish to access group resources through the UI. Users can't be manually added as members. diff --git a/lib/api/package_files.rb b/lib/api/package_files.rb index 4a33f3e8af2..6d0c1f44a36 100644 --- a/lib/api/package_files.rb +++ b/lib/api/package_files.rb @@ -30,6 +30,29 @@ module API present paginate(package.package_files), with: ::API::Entities::PackageFile end + + desc 'Remove a package file' do + detail 'This feature was introduced in GitLab 13.12' + end + params do + requires :package_file_id, type: Integer, desc: 'The ID of a package file' + end + delete ':id/packages/:package_id/package_files/:package_file_id' do + authorize_destroy_package!(user_project) + + # We want to make sure the file belongs to the declared package + # so we look up the package before looking up the file. + package = ::Packages::PackageFinder + .new(user_project, params[:package_id]).execute + + not_found! unless package + + package_file = package.package_files.find_by_id(params[:package_file_id]) + + not_found! unless package_file + + destroy_conditionally!(package_file) + end end end end diff --git a/lib/api/settings.rb b/lib/api/settings.rb index f54b92134dc..c32825a556f 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -171,6 +171,7 @@ module API optional :wiki_page_max_content_bytes, type: Integer, desc: "Maximum wiki page content size in bytes" optional :require_admin_approval_after_user_signup, type: Boolean, desc: 'Require explicit admin approval for new signups' optional :whats_new_variant, type: String, values: ApplicationSetting.whats_new_variants.keys, desc: "What's new variant, possible values: `all_tiers`, `current_tier`, and `disabled`." + optional :floc_enabled, type: Grape::API::Boolean, desc: 'Enable FloC (Federated Learning of Cohorts)' ApplicationSetting::SUPPORTED_KEY_TYPES.each do |type| optional :"#{type}_key_restriction", diff --git a/lib/gitlab/usage_data_counters/known_events/epic_board_events.yml b/lib/gitlab/usage_data_counters/known_events/epic_board_events.yml new file mode 100644 index 00000000000..281db441829 --- /dev/null +++ b/lib/gitlab/usage_data_counters/known_events/epic_board_events.yml @@ -0,0 +1,22 @@ +# Epic board events +# +# We are using the same slot of issue events 'project_management' for +# epic events to allow data aggregation. +# More information in: https://gitlab.com/gitlab-org/gitlab/-/issues/322405 +- name: g_project_management_users_creating_epic_boards + category: epic_boards_usage + redis_slot: project_management + aggregation: daily + feature_flag: track_epic_boards_activity + +- name: g_project_management_users_viewing_epic_boards + category: epic_boards_usage + redis_slot: project_management + aggregation: daily + feature_flag: track_epic_boards_activity + +- name: g_project_management_users_updating_epic_board_names + category: epic_boards_usage + redis_slot: project_management + aggregation: daily + feature_flag: track_epic_boards_activity diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 24f71c8c45d..eec9886323d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -11738,9 +11738,6 @@ msgstr "" msgid "Duration" msgstr "" -msgid "Duration for the last 30 commits" -msgstr "" - msgid "During this process, you’ll be asked for URLs from GitLab’s side. Use the URLs shown below." msgstr "" @@ -14097,6 +14094,15 @@ msgstr "" msgid "Flags" msgstr "" +msgid "FloC|Configure whether you want to participate in FloC." +msgstr "" + +msgid "FloC|Enable FloC (Federated Learning of Cohorts)" +msgstr "" + +msgid "FloC|Federated Learning of Cohorts" +msgstr "" + msgid "FlowdockService|1b609b52537..." msgstr "" @@ -14856,10 +14862,10 @@ msgstr "" msgid "Geo|Verification failed - %{error}" msgstr "" -msgid "Geo|Verification status" +msgid "Geo|Verification information" msgstr "" -msgid "Geo|Verificaton information" +msgid "Geo|Verification status" msgstr "" msgid "Geo|Waiting for scheduler" @@ -23668,6 +23674,9 @@ msgstr "" msgid "Pipeline Schedules" msgstr "" +msgid "Pipeline durations for the last 30 commits" +msgstr "" + msgid "Pipeline minutes quota" msgstr "" diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index fec81c6a979..0235d7eb95a 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -1027,4 +1027,44 @@ RSpec.describe ApplicationController do get :index end end + + describe 'setting permissions-policy header' do + controller do + skip_before_action :authenticate_user! + + def index + render html: 'It is a flock of sheep, not a floc of sheep.' + end + end + + before do + routes.draw do + get 'index' => 'anonymous#index' + end + end + + context 'with FloC enabled' do + before do + stub_application_setting floc_enabled: true + end + + it 'does not set the Permissions-Policy header' do + get :index + + expect(response.headers['Permissions-Policy']).to eq(nil) + end + end + + context 'with FloC disabled' do + before do + stub_application_setting floc_enabled: false + end + + it 'sets the Permissions-Policy header' do + get :index + + expect(response.headers['Permissions-Policy']).to eq('interest-cohort=()') + end + end + end end diff --git a/spec/features/projects/graph_spec.rb b/spec/features/projects/graph_spec.rb index 72df84bf905..7e039a087c7 100644 --- a/spec/features/projects/graph_spec.rb +++ b/spec/features/projects/graph_spec.rb @@ -75,7 +75,7 @@ RSpec.describe 'Project Graph', :js do expect(page).to have_content 'Last week' expect(page).to have_content 'Last month' expect(page).to have_content 'Last year' - expect(page).to have_content 'Duration for the last 30 commits' + expect(page).to have_content 'Pipeline durations for the last 30 commits' end end end diff --git a/spec/frontend/static_site_editor/mock_data.js b/spec/frontend/static_site_editor/mock_data.js index 8bc65c6ce31..8d64e1799b8 100644 --- a/spec/frontend/static_site_editor/mock_data.js +++ b/spec/frontend/static_site_editor/mock_data.js @@ -55,7 +55,7 @@ export const mergeRequestTemplates = [ export const submitChangesError = 'Could not save changes'; export const commitBranchResponse = { - web_url: '/tree/root-master-patch-88195', + web_url: '/tree/root-main-patch-88195', }; export const commitMultipleResponse = { short_id: 'ed899a2f4b5', @@ -84,8 +84,8 @@ export const mounts = [ }, ]; -export const branch = 'master'; +export const branch = 'main'; -export const baseUrl = '/user1/project1/-/sse/master%2Ftest.md'; +export const baseUrl = '/user1/project1/-/sse/main%2Ftest.md'; export const imageRoot = 'source/images/'; diff --git a/spec/frontend/static_site_editor/pages/home_spec.js b/spec/frontend/static_site_editor/pages/home_spec.js index 0936ba3011c..eb056469603 100644 --- a/spec/frontend/static_site_editor/pages/home_spec.js +++ b/spec/frontend/static_site_editor/pages/home_spec.js @@ -275,6 +275,7 @@ describe('static_site_editor/pages/home', () => { formattedMarkdown, project, sourcePath, + targetBranch: branch, username, images, mergeRequestMeta, diff --git a/spec/frontend/static_site_editor/services/generate_branch_name_spec.js b/spec/frontend/static_site_editor/services/generate_branch_name_spec.js index 0624fc3b7b4..7e437506a16 100644 --- a/spec/frontend/static_site_editor/services/generate_branch_name_spec.js +++ b/spec/frontend/static_site_editor/services/generate_branch_name_spec.js @@ -1,7 +1,7 @@ -import { DEFAULT_TARGET_BRANCH, BRANCH_SUFFIX_COUNT } from '~/static_site_editor/constants'; +import { BRANCH_SUFFIX_COUNT } from '~/static_site_editor/constants'; import generateBranchName from '~/static_site_editor/services/generate_branch_name'; -import { username } from '../mock_data'; +import { username, branch as targetBranch } from '../mock_data'; describe('generateBranchName', () => { const timestamp = 12345678901234; @@ -11,11 +11,11 @@ describe('generateBranchName', () => { }); it('generates a name that includes the username and target branch', () => { - expect(generateBranchName(username)).toMatch(`${username}-${DEFAULT_TARGET_BRANCH}`); + expect(generateBranchName(username, targetBranch)).toMatch(`${username}-${targetBranch}`); }); it(`adds the first ${BRANCH_SUFFIX_COUNT} numbers of the current timestamp`, () => { - expect(generateBranchName(username)).toMatch( + expect(generateBranchName(username, targetBranch)).toMatch( timestamp.toString().substring(BRANCH_SUFFIX_COUNT), ); }); diff --git a/spec/frontend/static_site_editor/services/renderers/render_image_spec.js b/spec/frontend/static_site_editor/services/renderers/render_image_spec.js index e9e40835982..d3298aa0b26 100644 --- a/spec/frontend/static_site_editor/services/renderers/render_image_spec.js +++ b/spec/frontend/static_site_editor/services/renderers/render_image_spec.js @@ -47,11 +47,11 @@ describe('rich_content_editor/renderers/render_image', () => { it.each` destination | isAbsolute | src ${'http://test.host/absolute/path/to/image.png'} | ${true} | ${'http://test.host/absolute/path/to/image.png'} - ${'/relative/path/to/image.png'} | ${false} | ${'http://test.host/user1/project1/-/raw/master/default/source/relative/path/to/image.png'} - ${'/target/image.png'} | ${false} | ${'http://test.host/user1/project1/-/raw/master/source/with/target/image.png'} - ${'relative/to/current/image.png'} | ${false} | ${'http://test.host/user1/project1/-/raw/master/relative/to/current/image.png'} - ${'./relative/to/current/image.png'} | ${false} | ${'http://test.host/user1/project1/-/raw/master/./relative/to/current/image.png'} - ${'../relative/to/current/image.png'} | ${false} | ${'http://test.host/user1/project1/-/raw/master/../relative/to/current/image.png'} + ${'/relative/path/to/image.png'} | ${false} | ${'http://test.host/user1/project1/-/raw/main/default/source/relative/path/to/image.png'} + ${'/target/image.png'} | ${false} | ${'http://test.host/user1/project1/-/raw/main/source/with/target/image.png'} + ${'relative/to/current/image.png'} | ${false} | ${'http://test.host/user1/project1/-/raw/main/relative/to/current/image.png'} + ${'./relative/to/current/image.png'} | ${false} | ${'http://test.host/user1/project1/-/raw/main/./relative/to/current/image.png'} + ${'../relative/to/current/image.png'} | ${false} | ${'http://test.host/user1/project1/-/raw/main/../relative/to/current/image.png'} `('returns an image with the correct attributes', ({ destination, isAbsolute, src }) => { node.destination = destination; diff --git a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js index d4cbc5d235e..d9bceb76a37 100644 --- a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js +++ b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js @@ -3,7 +3,6 @@ import Api from '~/api'; import { convertObjectPropsToSnakeCase } from '~/lib/utils/common_utils'; import { - DEFAULT_TARGET_BRANCH, SUBMIT_CHANGES_BRANCH_ERROR, SUBMIT_CHANGES_COMMIT_ERROR, SUBMIT_CHANGES_MERGE_REQUEST_ERROR, @@ -25,6 +24,7 @@ import { createMergeRequestResponse, mergeRequestMeta, sourcePath, + branch as targetBranch, sourceContentYAML as content, trackingCategory, images, @@ -33,7 +33,7 @@ import { jest.mock('~/static_site_editor/services/generate_branch_name'); describe('submitContentChanges', () => { - const branch = 'branch-name'; + const sourceBranch = 'branch-name'; let trackingSpy; let origPage; @@ -41,6 +41,7 @@ describe('submitContentChanges', () => { username, projectId, sourcePath, + targetBranch, content, images, mergeRequestMeta, @@ -54,7 +55,7 @@ describe('submitContentChanges', () => { .spyOn(Api, 'createProjectMergeRequest') .mockResolvedValue({ data: createMergeRequestResponse }); - generateBranchName.mockReturnValue(branch); + generateBranchName.mockReturnValue(sourceBranch); origPage = document.body.dataset.page; document.body.dataset.page = trackingCategory; @@ -69,8 +70,8 @@ describe('submitContentChanges', () => { it('creates a branch named after the username and target branch', () => { return submitContentChanges(buildPayload()).then(() => { expect(Api.createBranch).toHaveBeenCalledWith(projectId, { - ref: DEFAULT_TARGET_BRANCH, - branch, + ref: targetBranch, + branch: sourceBranch, }); }); }); @@ -86,7 +87,7 @@ describe('submitContentChanges', () => { describe('committing markdown formatting changes', () => { const formattedMarkdown = `formatted ${content}`; const commitPayload = { - branch, + branch: sourceBranch, commit_message: `${DEFAULT_FORMATTING_CHANGES_COMMIT_MESSAGE}\n\n${DEFAULT_FORMATTING_CHANGES_COMMIT_DESCRIPTION}`, actions: [ { @@ -116,7 +117,7 @@ describe('submitContentChanges', () => { it('commits the content changes to the branch when creating branch succeeds', () => { return submitContentChanges(buildPayload()).then(() => { expect(Api.commitMultiple).toHaveBeenCalledWith(projectId, { - branch, + branch: sourceBranch, commit_message: mergeRequestMeta.title, actions: [ { @@ -140,7 +141,7 @@ describe('submitContentChanges', () => { const payload = buildPayload({ content: contentWithoutImages }); return submitContentChanges(payload).then(() => { expect(Api.commitMultiple).toHaveBeenCalledWith(projectId, { - branch, + branch: sourceBranch, commit_message: mergeRequestMeta.title, actions: [ { @@ -169,8 +170,8 @@ describe('submitContentChanges', () => { convertObjectPropsToSnakeCase({ title, description, - targetBranch: DEFAULT_TARGET_BRANCH, - sourceBranch: branch, + targetBranch, + sourceBranch, }), ); }); @@ -194,7 +195,7 @@ describe('submitContentChanges', () => { }); it('returns the branch name', () => { - expect(result).toMatchObject({ branch: { label: branch } }); + expect(result).toMatchObject({ branch: { label: sourceBranch } }); }); it('returns commit short id and web url', () => { diff --git a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb index 9fc28f6c4ec..4efacae0a48 100644 --- a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb @@ -45,6 +45,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s 'quickactions', 'pipeline_authoring', 'epics_usage', + 'epic_boards_usage', 'secure' ) end diff --git a/spec/requests/api/package_files_spec.rb b/spec/requests/api/package_files_spec.rb index 11170066d6e..137ded050c5 100644 --- a/spec/requests/api/package_files_spec.rb +++ b/spec/requests/api/package_files_spec.rb @@ -7,13 +7,13 @@ RSpec.describe API::PackageFiles do let(:project) { create(:project, :public) } let(:package) { create(:maven_package, project: project) } - before do - project.add_developer(user) - end - describe 'GET /projects/:id/packages/:package_id/package_files' do let(:url) { "/projects/#{project.id}/packages/#{package.id}/package_files" } + before do + project.add_developer(user) + end + context 'without the need for a license' do context 'project is public' do it 'returns 200' do @@ -78,4 +78,77 @@ RSpec.describe API::PackageFiles do end end end + + describe 'DELETE /projects/:id/packages/:package_id/package_files/:package_file_id' do + let(:package_file_id) { package.package_files.first.id } + let(:url) { "/projects/#{project.id}/packages/#{package.id}/package_files/#{package_file_id}" } + + subject(:api_request) { delete api(url, user) } + + context 'project is public' do + context 'without user' do + let(:user) { nil } + + it 'returns 403 for non authenticated user', :aggregate_failures do + expect { api_request }.not_to change { package.package_files.count } + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + it 'returns 403 for a user without access to the project', :aggregate_failures do + expect { api_request }.not_to change { package.package_files.count } + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + + context 'project is private' do + let_it_be_with_refind(:project) { create(:project, :private) } + + it 'returns 404 for a user without access to the project', :aggregate_failures do + expect { api_request }.not_to change { package.package_files.count } + + expect(response).to have_gitlab_http_status(:not_found) + end + + it 'returns 403 for a user without enough permissions', :aggregate_failures do + project.add_developer(user) + + expect { api_request }.not_to change { package.package_files.count } + + expect(response).to have_gitlab_http_status(:forbidden) + end + + it 'returns 204', :aggregate_failures do + project.add_maintainer(user) + + expect { api_request }.to change { package.package_files.count }.by(-1) + + expect(response).to have_gitlab_http_status(:no_content) + end + + context 'without user' do + let(:user) { nil } + + it 'returns 404 for non authenticated user', :aggregate_failures do + expect { api_request }.not_to change { package.package_files.count } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'invalid file' do + let(:url) { "/projects/#{project.id}/packages/#{package.id}/package_files/999999" } + + it 'returns 404 when the package file does not exist', :aggregate_failures do + project.add_maintainer(user) + + expect { api_request }.not_to change { package.package_files.count } + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end end |