summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-03-09 03:09:18 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-03-09 03:09:18 +0000
commit276941b2c436678b956025ae2958e11ccbeac55d (patch)
tree5e88dd0b0e167972b4433b31c4381d7be66187e0
parent25096948f0f1837d0217cbd45394aa875756f054 (diff)
downloadgitlab-ce-276941b2c436678b956025ae2958e11ccbeac55d.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue10
-rw-r--r--app/models/packages/pypi/metadatum.rb2
-rw-r--r--app/services/packages/pypi/create_package_service.rb2
-rw-r--r--app/views/admin/application_settings/_prometheus.html.haml2
-rw-r--r--app/views/projects/_merge_request_merge_method_settings.html.haml4
-rw-r--r--db/migrate/20220304152729_add_default_to_required_python_on_packages_pypi_metadata.rb11
-rw-r--r--db/post_migrate/20220308000205_drop_old_index_security_ci_builds_on_name_and_id_parser_features.rb26
-rw-r--r--db/schema_migrations/202203041527291
-rw-r--r--db/schema_migrations/202203080002051
-rw-r--r--db/structure.sql4
-rw-r--r--doc/administration/audit_event_streaming.md181
-rw-r--r--doc/administration/gitaly/troubleshooting.md42
-rw-r--r--doc/api/packages/pypi.md1
-rw-r--r--doc/operations/feature_flags.md36
-rw-r--r--doc/user/clusters/agent/install/index.md2
-rw-r--r--doc/user/group/index.md2
-rw-r--r--doc/user/profile/personal_access_tokens.md4
-rw-r--r--lib/api/internal/base.rb6
-rw-r--r--lib/api/pypi_packages.rb2
-rw-r--r--lib/banzai/filter/front_matter_filter.rb5
-rw-r--r--lib/gitlab/front_matter.rb6
-rw-r--r--lib/gitlab/wiki_pages/front_matter_parser.rb2
-rw-r--r--locale/gitlab.pot8
-rw-r--r--qa/qa/resource/group_base.rb2
-rw-r--r--qa/qa/resource/reusable_collection.rb3
-rw-r--r--spec/features/projects/environments/environments_spec.rb6
-rw-r--r--spec/frontend/environments/environment_actions_spec.js17
-rw-r--r--spec/lib/banzai/filter/front_matter_filter_spec.rb53
-rw-r--r--spec/models/packages/pypi/metadatum_spec.rb3
-rw-r--r--spec/requests/api/pypi_packages_spec.rb8
-rw-r--r--spec/services/packages/pypi/create_package_service_spec.rb16
-rw-r--r--spec/support/shared_examples/sends_git_audit_streaming_event_shared_examples.rb61
32 files changed, 458 insertions, 71 deletions
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
index 98c95507168..c7e024aadec 100644
--- a/app/assets/javascripts/environments/components/environment_actions.vue
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -1,5 +1,6 @@
<script>
import { GlDropdown, GlDropdownItem, GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import { formatTime } from '~/lib/utils/datetime_utility';
import { __, s__, sprintf } from '~/locale';
import eventHub from '../event_hub';
@@ -37,7 +38,7 @@ export default {
},
},
methods: {
- onClickAction(action) {
+ async onClickAction(action) {
if (action.scheduledAt) {
const confirmationMessage = sprintf(
s__(
@@ -45,9 +46,10 @@ export default {
),
{ jobName: action.name },
);
- // https://gitlab.com/gitlab-org/gitlab-foss/issues/52156
- // eslint-disable-next-line no-alert
- if (!window.confirm(confirmationMessage)) {
+
+ const confirmed = await confirmAction(confirmationMessage);
+
+ if (!confirmed) {
return;
}
}
diff --git a/app/models/packages/pypi/metadatum.rb b/app/models/packages/pypi/metadatum.rb
index 2e4d61eaf53..ff247fedb59 100644
--- a/app/models/packages/pypi/metadatum.rb
+++ b/app/models/packages/pypi/metadatum.rb
@@ -6,7 +6,7 @@ class Packages::Pypi::Metadatum < ApplicationRecord
belongs_to :package, -> { where(package_type: :pypi) }, inverse_of: :pypi_metadatum
validates :package, presence: true
- validates :required_python, length: { maximum: 255 }, allow_blank: true
+ validates :required_python, length: { maximum: 255 }, allow_nil: false
validate :pypi_package_type
diff --git a/app/services/packages/pypi/create_package_service.rb b/app/services/packages/pypi/create_package_service.rb
index b988c191734..5d7e967ceb0 100644
--- a/app/services/packages/pypi/create_package_service.rb
+++ b/app/services/packages/pypi/create_package_service.rb
@@ -9,7 +9,7 @@ module Packages
::Packages::Package.transaction do
meta = Packages::Pypi::Metadatum.new(
package: created_package,
- required_python: params[:requires_python]
+ required_python: params[:requires_python] || ''
)
unless meta.valid?
diff --git a/app/views/admin/application_settings/_prometheus.html.haml b/app/views/admin/application_settings/_prometheus.html.haml
index 08befa59952..11830fac336 100644
--- a/app/views/admin/application_settings/_prometheus.html.haml
+++ b/app/views/admin/application_settings/_prometheus.html.haml
@@ -13,7 +13,7 @@
- unless Gitlab::Metrics.metrics_folder_present?
.form-text.text-muted
%strong.cred= _("WARNING:")
- = _("Environment variable %{code_start}%{environment_variable}%{code_end} does not exist or is not pointing to a valid directory.").html_safe % { environment_variable: prometheus_multiproc_dir, code_start: '<code>'.html_safe, code_end: '</code>'.html_safe }
+ = _("Environment variable %{environment_variable} does not exist or is not pointing to a valid directory.").html_safe % { environment_variable: '<code>prometheus_multiproc_dir</code>'.html_safe }
= link_to sprite_icon('question-o'), help_page_path('administration/monitoring/prometheus/gitlab_metrics', anchor: 'metrics-shared-directory')
.form-group
= f.label :metrics_method_call_threshold, _('Method call threshold (ms)'), class: 'label-bold'
diff --git a/app/views/projects/_merge_request_merge_method_settings.html.haml b/app/views/projects/_merge_request_merge_method_settings.html.haml
index 778586a592e..250f7e94e84 100644
--- a/app/views/projects/_merge_request_merge_method_settings.html.haml
+++ b/app/views/projects/_merge_request_merge_method_settings.html.haml
@@ -19,9 +19,9 @@
.text-secondary
= s_('ProjectSettings|Every merge creates a merge commit.')
%br
- = s_('ProjectSettings|Fast-forward merges only.')
+ = s_('ProjectSettings|Merging is only allowed when the source branch is up-to-date with its target.')
%br
- = s_('ProjectSettings|When there is a merge conflict, the user is given the option to rebase.')
+ = s_('ProjectSettings|When semi-linear merge is not possible, the user is given the option to rebase.')
.form-check.mb-2
= form.radio_button :merge_method, :ff, class: "js-merge-method-radio form-check-input", data: { qa_selector: 'merge_ff_radio' }
diff --git a/db/migrate/20220304152729_add_default_to_required_python_on_packages_pypi_metadata.rb b/db/migrate/20220304152729_add_default_to_required_python_on_packages_pypi_metadata.rb
new file mode 100644
index 00000000000..56297565cb4
--- /dev/null
+++ b/db/migrate/20220304152729_add_default_to_required_python_on_packages_pypi_metadata.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddDefaultToRequiredPythonOnPackagesPypiMetadata < Gitlab::Database::Migration[1.0]
+ def up
+ change_column_default(:packages_pypi_metadata, :required_python, '')
+ end
+
+ def down
+ change_column_default(:packages_pypi_metadata, :required_python, nil)
+ end
+end
diff --git a/db/post_migrate/20220308000205_drop_old_index_security_ci_builds_on_name_and_id_parser_features.rb b/db/post_migrate/20220308000205_drop_old_index_security_ci_builds_on_name_and_id_parser_features.rb
new file mode 100644
index 00000000000..4b895c291d8
--- /dev/null
+++ b/db/post_migrate/20220308000205_drop_old_index_security_ci_builds_on_name_and_id_parser_features.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class DropOldIndexSecurityCiBuildsOnNameAndIdParserFeatures < Gitlab::Database::Migration[1.0]
+ TABLE = "ci_builds"
+ COLUMNS = %i[name id]
+ INDEX_NAME = "index_security_ci_builds_on_name_and_id_parser_features_old"
+ CONSTRAINTS = "(name::text = ANY (ARRAY['container_scanning'::character varying::text,
+ 'dast'::character varying::text,
+ 'dependency_scanning'::character varying::text,
+ 'license_management'::character varying::text,
+ 'sast'::character varying::text,
+ 'secret_detection'::character varying::text,
+ 'coverage_fuzzing'::character varying::text,
+ 'license_scanning'::character varying::text])
+ ) AND type::text = 'Ci::Build'::text"
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index(TABLE, COLUMNS, name: INDEX_NAME, where: CONSTRAINTS)
+ end
+
+ def down
+ add_concurrent_index(TABLE, COLUMNS, name: INDEX_NAME, where: CONSTRAINTS)
+ end
+end
diff --git a/db/schema_migrations/20220304152729 b/db/schema_migrations/20220304152729
new file mode 100644
index 00000000000..021d4e5ad27
--- /dev/null
+++ b/db/schema_migrations/20220304152729
@@ -0,0 +1 @@
+483f8299688a6e24fa77867b7dab8a2dad0c2b7ebe43c56c81c02ab1e0dc4674 \ No newline at end of file
diff --git a/db/schema_migrations/20220308000205 b/db/schema_migrations/20220308000205
new file mode 100644
index 00000000000..27caf959eb9
--- /dev/null
+++ b/db/schema_migrations/20220308000205
@@ -0,0 +1 @@
+c30b1b36ec83df1b4fdf0c3c28656b158beab4f2188875898182c2dfbd073c80 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index bbeecb69858..0a4b3bec84a 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -18325,7 +18325,7 @@ ALTER SEQUENCE packages_packages_id_seq OWNED BY packages_packages.id;
CREATE TABLE packages_pypi_metadata (
package_id bigint NOT NULL,
- required_python text,
+ required_python text DEFAULT ''::text,
CONSTRAINT check_0d9aed55b2 CHECK ((required_python IS NOT NULL)),
CONSTRAINT check_379019d5da CHECK ((char_length(required_python) <= 255))
);
@@ -28939,8 +28939,6 @@ CREATE INDEX index_secure_ci_builds_on_user_id_name_created_at ON ci_builds USIN
CREATE INDEX index_security_ci_builds_on_name_and_id_parser_features ON ci_builds USING btree (name, id) WHERE (((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('sast'::character varying)::text, ('secret_detection'::character varying)::text, ('coverage_fuzzing'::character varying)::text, ('license_scanning'::character varying)::text, ('apifuzzer_fuzz'::character varying)::text, ('apifuzzer_fuzz_dnd'::character varying)::text])) AND ((type)::text = 'Ci::Build'::text));
-CREATE INDEX index_security_ci_builds_on_name_and_id_parser_features_old ON ci_builds USING btree (name, id) WHERE (((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('sast'::character varying)::text, ('secret_detection'::character varying)::text, ('coverage_fuzzing'::character varying)::text, ('license_scanning'::character varying)::text])) AND ((type)::text = 'Ci::Build'::text));
-
CREATE INDEX index_security_findings_on_confidence ON security_findings USING btree (confidence);
CREATE INDEX index_security_findings_on_project_fingerprint ON security_findings USING btree (project_fingerprint);
diff --git a/doc/administration/audit_event_streaming.md b/doc/administration/audit_event_streaming.md
index 3bdc67e5a69..4f2fc8c26e2 100644
--- a/doc/administration/audit_event_streaming.md
+++ b/doc/administration/audit_event_streaming.md
@@ -78,3 +78,184 @@ token is generated when the event destination is created and cannot be changed.
Each streamed event contains a random alphanumeric identifier for the `X-Gitlab-Event-Streaming-Token` HTTP header that can be verified against
the destination's value when [listing streaming destinations](#list-currently-enabled-streaming-destinations).
+
+## Audit event streaming on Git operations
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332747) in GitLab 14.9 [with a flag](../administration/feature_flags.md) named `audit_event_streaming_git_operations`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](feature_flags.md) named `audit_event_streaming_git_operations`. On GitLab.com, this feature is not available.
+
+Streaming audit events can be sent when signed-in users push or pull a project's remote Git repositories:
+
+- [Using SSH](../ssh/index.md).
+- Using HTTP or HTTPS.
+- Using the **Download** button (**{download}**) in GitLab UI.
+
+Audit events are not captured for users that are not signed in. For example, when downloading a public project.
+
+To configure streaming audit events for Git operations, see [Add a new event streaming destination](#add-a-new-event-streaming-destination).
+
+### Request headers
+
+Request headers are formatted as follows:
+
+```plaintext
+POST /logs HTTP/1.1
+Host: <DESTINATION_HOST>
+Content-Type: application/x-www-form-urlencoded
+X-Gitlab-Event-Streaming-Token: <DESTINATION_TOKEN>
+```
+
+### Example responses for SSH events
+
+Fetch:
+
+```json
+{
+ "id": 1,
+ "author_id": 1,
+ "entity_id": 29,
+ "entity_type": "Project",
+ "details": {
+ "author_name": "Administrator",
+ "target_id": 29,
+ "target_type": "Project",
+ "target_details": "example-project",
+ "custom_message": {
+ "protocol": "ssh",
+ "action": "git-upload-pack"
+ },
+ "ip_address": "127.0.0.1",
+ "entity_path": "example-group/example-project"
+ },
+ "ip_address": "127.0.0.1",
+ "author_name": "Administrator",
+ "entity_path": "example-group/example-project",
+ "target_details": "example-project",
+ "created_at": "2022-02-23T06:21:05.283Z",
+ "target_type": "Project",
+ "target_id": 29
+}
+```
+
+Push:
+
+```json
+{
+ "id": 1,
+ "author_id": 1,
+ "entity_id": 29,
+ "entity_type": "Project",
+ "details": {
+ "author_name": "Administrator",
+ "target_id": 29,
+ "target_type": "Project",
+ "target_details": "example-project",
+ "custom_message": {
+ "protocol": "ssh",
+ "action": "git-receive-pack"
+ },
+ "ip_address": "127.0.0.1",
+ "entity_path": "example-group/example-project"
+ },
+ "ip_address": "127.0.0.1",
+ "author_name": "Administrator",
+ "entity_path": "example-group/example-project",
+ "target_details": "example-project",
+ "created_at": "2022-02-23T06:23:08.746Z",
+ "target_type": "Project",
+ "target_id": 29
+}
+```
+
+### Example responses for HTTP and HTTPS events
+
+Fetch:
+
+```json
+{
+ "id": 1,
+ "author_id": 1,
+ "entity_id": 29,
+ "entity_type": "Project",
+ "details": {
+ "author_name": "Administrator",
+ "target_id": 29,
+ "target_type": "Project",
+ "target_details": "example-project",
+ "custom_message": {
+ "protocol": "http",
+ "action": "git-upload-pack"
+ },
+ "ip_address": "127.0.0.1",
+ "entity_path": "example-group/example-project"
+ },
+ "ip_address": "127.0.0.1",
+ "author_name": "Administrator",
+ "entity_path": "example-group/example-project",
+ "target_details": "example-project",
+ "created_at": "2022-02-23T06:25:43.938Z",
+ "target_type": "Project",
+ "target_id": 29
+}
+```
+
+Push:
+
+```json
+{
+ "id": 1,
+ "author_id": 1,
+ "entity_id": 29,
+ "entity_type": "Project",
+ "details": {
+ "author_name": "Administrator",
+ "target_id": 29,
+ "target_type": "Project",
+ "target_details": "example-project",
+ "custom_message": {
+ "protocol": "http",
+ "action": "git-receive-pack"
+ },
+ "ip_address": "127.0.0.1",
+ "entity_path": "example-group/example-project"
+ },
+ "ip_address": "127.0.0.1",
+ "author_name": "Administrator",
+ "entity_path": "example-group/example-project",
+ "target_details": "example-project",
+ "created_at": "2022-02-23T06:26:29.294Z",
+ "target_type": "Project",
+ "target_id": 29
+}
+```
+
+### Example responses for events from GitLab UI download button
+
+Fetch:
+
+```json
+{
+ "id": 1,
+ "author_id": 99,
+ "entity_id": 29,
+ "entity_type": "Project",
+ "details": {
+ "custom_message": "Repository Download Started",
+ "author_name": "example_username",
+ "target_id": 29,
+ "target_type": "Project",
+ "target_details": "example-group/example-project",
+ "ip_address": "127.0.0.1",
+ "entity_path": "example-group/example-project"
+ },
+ "ip_address": "127.0.0.1",
+ "author_name": "example_username",
+ "entity_path": "example-group/example-project",
+ "target_details": "example-group/example-project",
+ "created_at": "2022-02-23T06:27:17.873Z",
+ "target_type": "Project",
+ "target_id": 29
+}
+```
diff --git a/doc/administration/gitaly/troubleshooting.md b/doc/administration/gitaly/troubleshooting.md
index b2783d3bab3..516af4ca469 100644
--- a/doc/administration/gitaly/troubleshooting.md
+++ b/doc/administration/gitaly/troubleshooting.md
@@ -610,3 +610,45 @@ Possible solutions:
- Provision larger VMs to gain access to larger network traffic allowances.
- Use your cloud service's monitoring and logging to check that the Praefect nodes are not exhausting their traffic allowances.
+
+## Profiling Gitaly
+
+Gitaly exposes several of Golang's built-in performance profiling tools on the Prometheus listen port. For example, if Prometheus is listening
+on port `9236` of the GitLab server:
+
+- Get a list of running `goroutines` and their backtraces:
+
+ ```shell
+ curl --output goroutines.txt "http://<gitaly_server>:9236/debug/pprof/goroutine?debug=2"
+ ```
+
+- Run a CPU profile for 30 seconds:
+
+ ```shell
+ curl --output cpu.bin "http://<gitaly_server>:9236/debug/pprof/profile"
+ ```
+
+- Profile heap memory usage:
+
+ ```shell
+ curl --output heap.bin "http://<gitaly_server>:9236/debug/pprof/heap"
+ ```
+
+- Record a 5 second execution trace. This will impact Gitaly's performance while running:
+
+ ```shell
+ curl --output trace.bin "http://<gitaly_server>:9236/debug/pprof/trace?seconds=5"
+ ```
+
+On a host with `go` installed, the CPU profile and heap profile can be viewed in a browser:
+
+```shell
+go tool pprof -http=:8001 cpu.bin
+go tool pprof -http=:8001 heap.bin
+```
+
+Execution traces can be viewed by running:
+
+```shell
+go tool trace heap.bin
+```
diff --git a/doc/api/packages/pypi.md b/doc/api/packages/pypi.md
index 592b976da59..5ed162a3d05 100644
--- a/doc/api/packages/pypi.md
+++ b/doc/api/packages/pypi.md
@@ -175,6 +175,7 @@ PUT projects/:id/packages/pypi
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | string | yes | The ID or full path of the project. |
+| `requires_python` | string | no | The PyPI required version. |
```shell
curl --request PUT \
diff --git a/doc/operations/feature_flags.md b/doc/operations/feature_flags.md
index 95472f03f7f..ab4f000743c 100644
--- a/doc/operations/feature_flags.md
+++ b/doc/operations/feature_flags.md
@@ -43,12 +43,7 @@ To create and enable a feature flag:
1. Enter a name that starts with a letter and contains only lowercase letters, digits, underscores (`_`),
or dashes (`-`), and does not end with a dash (`-`) or underscore (`_`).
1. Optional. Enter a description (255 characters maximum).
-1. Enter details about how the flag should be applied:
- - In GitLab 13.0 and earlier, add **Environment specs**. For each environment,
- include the **Status** (default enabled) and [**Rollout strategy**](#rollout-strategy-legacy)
- (defaults to **All users**).
- - In GitLab 13.1 and later, add Feature Flag [**Strategies**](#feature-flag-strategies).
- For each strategy, include the **Type** (defaults to [**All users**](#all-users))
+1. Add Feature Flag [**Strategies**](#feature-flag-strategies) to define how the flag should be applied. For each strategy, include the **Type** (defaults to [**All users**](#all-users))
and **Environments** (defaults to all environments).
1. Select **Create feature flag**.
@@ -235,35 +230,6 @@ To search for code references of a feature flag:
1. Select **More actions** (**{ellipsis_v}**).
1. Select **Search code references**.
-## Rollout strategy (legacy)
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8240) in GitLab 12.2.
-> - [Made read-only](https://gitlab.com/gitlab-org/gitlab/-/issues/220228) in GitLab 13.4.
-
-In GitLab 13.0 and earlier, the **Rollout strategy** setting affects which users experience
-the feature as enabled. Choose the percentage of users that the feature is enabled
-for. The rollout strategy has no effect if the environment spec is disabled.
-
-It can be set to:
-
-- All users
-- [Percent of users](#percent-of-users)
- - Optionally, you can click the **Include additional user IDs** checkbox and add a list
- of specific users IDs to enable the feature for.
-- [User IDs](#user-ids)
-
-## Legacy feature flag migration
-
-Legacy feature flags became read-only in GitLab 13.4. GitLab 14.0 removes support for legacy feature
-flags. You must migrate your legacy feature flags to the new version. To do so, follow these steps:
-
-1. Take a screenshot of the legacy flag for tracking.
-1. Delete the flag through the API or UI (you don't need to alter the code).
-1. Create a new feature flag with the same name as the legacy flag you deleted. Make sure the
- strategies and environments match the deleted flag.
-
-See [this video tutorial](https://www.youtube.com/watch?v=CAJY2IGep7Y) for help with this migration.
-
## Disable a feature flag for a specific environment
In [GitLab 13.0 and earlier](https://gitlab.com/gitlab-org/gitlab/-/issues/8621),
diff --git a/doc/user/clusters/agent/install/index.md b/doc/user/clusters/agent/install/index.md
index 253bae8f576..869c9e33d13 100644
--- a/doc/user/clusters/agent/install/index.md
+++ b/doc/user/clusters/agent/install/index.md
@@ -104,7 +104,7 @@ Optionally, you can [customize the one-liner installation command](#customize-th
By default, the one-liner command generated by GitLab:
-- Creates a namespace for the deployment (`gitlab-kubernetes-agent`).
+- Creates a namespace for the deployment (`gitlab-agent`).
- Sets up a service account with `cluster-admin` rights (see [how to restrict this service account](#customize-the-permissions-for-the-agentk-service-account)).
- Creates a `Secret` resource for the agent's registration token.
- Creates a `Deployment` resource for the `agentk` pod.
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index 61ac8a65f90..00fa51eddc9 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -371,7 +371,7 @@ create a new group and transfer projects to it instead.
To change your group path (group URL):
1. Go to your group's **Settings > General** page.
-1. Expand the **Path, transfer, remove** section.
+1. Expand the **Advanced** section.
1. Under **Change group URL**, enter a new name.
1. Select **Change group URL**.
diff --git a/doc/user/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md
index 10d718fdf1a..1fbbe438370 100644
--- a/doc/user/profile/personal_access_tokens.md
+++ b/doc/user/profile/personal_access_tokens.md
@@ -25,8 +25,8 @@ Personal access tokens are:
- Used with a GitLab username to authenticate with GitLab features that require usernames. For example,
[GitLab managed Terraform state backend](../infrastructure/iac/terraform_state.md#using-a-gitlab-managed-terraform-state-backend-as-a-remote-data-source)
and [Docker container registry](../packages/container_registry/index.md#authenticate-with-the-container-registry),
-- Similar to [project access tokens](../project/settings/project_access_tokens.md), but are attached
- to a user rather than a project.
+- Similar to [project access tokens](../project/settings/project_access_tokens.md) and [group access tokens](../group/settings/group_access_tokens.md), but are attached
+ to a user rather than a project or group.
NOTE:
Though required, GitLab usernames are ignored when authenticating with a personal access token.
diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb
index 48157a91477..9c527f28d44 100644
--- a/lib/api/internal/base.rb
+++ b/lib/api/internal/base.rb
@@ -92,6 +92,8 @@ module API
payload[:git_config_options] << "receive.maxInputSize=#{receive_max_input_size.megabytes}"
end
+ send_git_audit_streaming_event(protocol: params[:protocol], action: params[:action])
+
response_with_status(**payload)
when ::Gitlab::GitAccessResult::CustomAction
response_with_status(code: 300, payload: check_result.payload, gl_console_messages: check_result.console_messages)
@@ -100,6 +102,10 @@ module API
end
end
+ def send_git_audit_streaming_event(msg)
+ # Defined in EE
+ end
+
def access_check!(actor, params)
access_checker = access_checker_for(actor, params[:protocol])
access_checker.check(params[:action], params[:changes]).tap do |result|
diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb
index 706c0702fce..86f36d4fc00 100644
--- a/lib/api/pypi_packages.rb
+++ b/lib/api/pypi_packages.rb
@@ -170,9 +170,9 @@ module API
params do
requires :content, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
- requires :requires_python, type: String
requires :name, type: String
requires :version, type: String
+ optional :requires_python, type: String
optional :md5_digest, type: String
optional :sha256_digest, type: String
end
diff --git a/lib/banzai/filter/front_matter_filter.rb b/lib/banzai/filter/front_matter_filter.rb
index 705400a5497..c788137e122 100644
--- a/lib/banzai/filter/front_matter_filter.rb
+++ b/lib/banzai/filter/front_matter_filter.rb
@@ -9,7 +9,10 @@ module Banzai
html.sub(Gitlab::FrontMatter::PATTERN) do |_match|
lang = $~[:lang].presence || lang_mapping[$~[:delim]]
- ["```#{lang}:frontmatter", $~[:front_matter].strip!, "```", "\n"].join("\n")
+ before = $~[:before]
+ before = "\n#{before}" if $~[:encoding].presence
+
+ "#{before}```#{lang}:frontmatter\n#{$~[:front_matter]}```\n"
end
end
end
diff --git a/lib/gitlab/front_matter.rb b/lib/gitlab/front_matter.rb
index 5c5c74ca1a0..093501e860b 100644
--- a/lib/gitlab/front_matter.rb
+++ b/lib/gitlab/front_matter.rb
@@ -11,12 +11,12 @@ module Gitlab
DELIM = Regexp.union(DELIM_LANG.keys)
PATTERN = %r{
- \A(?:[^\r\n]*coding:[^\r\n]*\R)? # optional encoding line
- \s*
+ \A(?<encoding>[^\r\n]*coding:[^\r\n]*\R)? # optional encoding line
+ (?<before>\s*)
^(?<delim>#{DELIM})[ \t]*(?<lang>\S*)\R # opening front matter marker (optional language specifier)
(?<front_matter>.*?) # front matter block content (not greedy)
^(\k<delim> | \.{3}) # closing front matter marker
- \s*
+ [^\S\r\n]*(\R|\z)
}mx.freeze
end
end
diff --git a/lib/gitlab/wiki_pages/front_matter_parser.rb b/lib/gitlab/wiki_pages/front_matter_parser.rb
index 0ceec39782c..071b0dde619 100644
--- a/lib/gitlab/wiki_pages/front_matter_parser.rb
+++ b/lib/gitlab/wiki_pages/front_matter_parser.rb
@@ -109,7 +109,7 @@ module Gitlab
end
def parse_front_matter_block
- wiki_content.match(Gitlab::FrontMatter::PATTERN) { |m| Block.new(*m.captures) } || Block.new
+ wiki_content.match(Gitlab::FrontMatter::PATTERN) { |m| Block.new(m[:delim], m[:lang], m[:front_matter]) } || Block.new
end
def strip_front_matter_block
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index beef1cbc9bc..30c90b53efc 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -13840,7 +13840,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variable %{code_start}%{environment_variable}%{code_end} does not exist or is not pointing to a valid directory."
+msgid "Environment variable %{environment_variable} does not exist or is not pointing to a valid directory."
msgstr ""
msgid "Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default."
@@ -28886,6 +28886,9 @@ msgstr ""
msgid "ProjectSettings|Merge suggestions"
msgstr ""
+msgid "ProjectSettings|Merging is only allowed when the source branch is up-to-date with its target."
+msgstr ""
+
msgid "ProjectSettings|No merge commits are created."
msgstr ""
@@ -29057,6 +29060,9 @@ msgstr ""
msgid "ProjectSettings|When merge request pipelines are enabled in the CI/CD configuration file, pipelines validate the combined results of the source and target branches. %{link_start}How to configure merge request pipelines?%{link_end}"
msgstr ""
+msgid "ProjectSettings|When semi-linear merge is not possible, the user is given the option to rebase."
+msgstr ""
+
msgid "ProjectSettings|When there is a merge conflict, the user is given the option to rebase."
msgstr ""
diff --git a/qa/qa/resource/group_base.rb b/qa/qa/resource/group_base.rb
index db6272ff749..889197a0373 100644
--- a/qa/qa/resource/group_base.rb
+++ b/qa/qa/resource/group_base.rb
@@ -65,7 +65,7 @@ module QA
end
def marked_for_deletion?
- !parse_body(api_get_from(api_get_path.to_s))[:marked_for_deletion_on].nil?
+ reload!.api_response[:marked_for_deletion_on].present?
end
# Get group badges
diff --git a/qa/qa/resource/reusable_collection.rb b/qa/qa/resource/reusable_collection.rb
index 27d34b16e2f..99a55800d1c 100644
--- a/qa/qa/resource/reusable_collection.rb
+++ b/qa/qa/resource/reusable_collection.rb
@@ -34,9 +34,8 @@ module QA
def remove_all_via_api!
instance.each_resource do |reuse_as, resource|
next QA::Runtime::Logger.debug("#{resource.class.name} reused as :#{reuse_as} has already been removed.") unless resource.exists?
- next if resource.respond_to?(:marked_for_deletion?) && resource.marked_for_deletion?
- if resource.reload!.api_resource[:marked_for_deletion_on].present?
+ if resource.respond_to?(:marked_for_deletion?) && resource.marked_for_deletion?
next QA::Runtime::Logger.debug("#{resource.class.name} reused as :#{reuse_as} is already scheduled to be removed.")
end
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 3b83c25b629..ca9aebf4336 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Environments page', :js do
+ include Spec::Support::Helpers::ModalHelpers
+
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:role) { :developer }
@@ -346,7 +348,9 @@ RSpec.describe 'Environments page', :js do
context 'when user played a delayed job immediately' do
before do
find(actions_button_selector).click
- accept_confirm { find(action_link_selector).click }
+ accept_gl_confirm do
+ find(action_link_selector).click
+ end
wait_for_requests
end
diff --git a/spec/frontend/environments/environment_actions_spec.js b/spec/frontend/environments/environment_actions_spec.js
index 336c207428e..ada79e2d415 100644
--- a/spec/frontend/environments/environment_actions_spec.js
+++ b/spec/frontend/environments/environment_actions_spec.js
@@ -7,8 +7,15 @@ import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import EnvironmentActions from '~/environments/components/environment_actions.vue';
import eventHub from '~/environments/event_hub';
import actionMutation from '~/environments/graphql/mutations/action.mutation.graphql';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import createMockApollo from 'helpers/mock_apollo_helper';
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal', () => {
+ return {
+ confirmAction: jest.fn(),
+ };
+});
+
const scheduledJobAction = {
name: 'scheduled action',
playPath: `${TEST_HOST}/scheduled/job/action`,
@@ -50,7 +57,7 @@ describe('EnvironmentActions Component', () => {
afterEach(() => {
wrapper.destroy();
- wrapper = null;
+ confirmAction.mockReset();
});
it('should render a dropdown button with 2 icons', () => {
@@ -105,7 +112,7 @@ describe('EnvironmentActions Component', () => {
let emitSpy;
const clickAndConfirm = async ({ confirm = true } = {}) => {
- jest.spyOn(window, 'confirm').mockImplementation(() => confirm);
+ confirmAction.mockResolvedValueOnce(confirm);
findDropdownItem(scheduledJobAction).vm.$emit('click');
await nextTick();
@@ -124,7 +131,7 @@ describe('EnvironmentActions Component', () => {
});
it('emits postAction event', () => {
- expect(window.confirm).toHaveBeenCalled();
+ expect(confirmAction).toHaveBeenCalled();
expect(emitSpy).toHaveBeenCalledWith({ endpoint: scheduledJobAction.playPath });
});
@@ -134,13 +141,13 @@ describe('EnvironmentActions Component', () => {
});
describe('when postAction event is denied', () => {
- beforeEach(() => {
+ beforeEach(async () => {
createComponentWithScheduledJobs({ mountFn: mount });
clickAndConfirm({ confirm: false });
});
it('does not emit postAction event if confirmation is cancelled', () => {
- expect(window.confirm).toHaveBeenCalled();
+ expect(confirmAction).toHaveBeenCalled();
expect(emitSpy).not.toHaveBeenCalled();
});
});
diff --git a/spec/lib/banzai/filter/front_matter_filter_spec.rb b/spec/lib/banzai/filter/front_matter_filter_spec.rb
index 1562c388296..f3543ab9582 100644
--- a/spec/lib/banzai/filter/front_matter_filter_spec.rb
+++ b/spec/lib/banzai/filter/front_matter_filter_spec.rb
@@ -105,6 +105,56 @@ RSpec.describe Banzai::Filter::FrontMatterFilter do
end
end
+ context 'source position mapping' do
+ it 'keeps spaces before and after' do
+ content = <<~MD
+
+
+ ---
+
+ foo: :foo_symbol
+
+ ---
+
+
+ # Header
+ MD
+
+ output = filter(content)
+
+ expect(output).to eq <<~MD
+
+
+ ```yaml:frontmatter
+
+ foo: :foo_symbol
+
+ ```
+
+
+ # Header
+ MD
+ end
+
+ it 'keeps an empty line in place of the encoding' do
+ content = <<~MD
+ # encoding: UTF-8
+ ---
+ foo: :foo_symbol
+ ---
+ MD
+
+ output = filter(content)
+
+ expect(output).to eq <<~MD
+
+ ```yaml:frontmatter
+ foo: :foo_symbol
+ ```
+ MD
+ end
+ end
+
context 'on content without front matter' do
it 'returns the content unmodified' do
content = <<~MD
@@ -119,7 +169,7 @@ RSpec.describe Banzai::Filter::FrontMatterFilter do
context 'on front matter without content' do
it 'converts YAML front matter to a fenced code block' do
- content = <<~MD
+ content = <<~MD.rstrip
---
foo: :foo_symbol
bar: :bar_symbol
@@ -134,7 +184,6 @@ RSpec.describe Banzai::Filter::FrontMatterFilter do
foo: :foo_symbol
bar: :bar_symbol
```
-
MD
end
end
diff --git a/spec/models/packages/pypi/metadatum_spec.rb b/spec/models/packages/pypi/metadatum_spec.rb
index 2c9893ef8f3..6c83c4ed143 100644
--- a/spec/models/packages/pypi/metadatum_spec.rb
+++ b/spec/models/packages/pypi/metadatum_spec.rb
@@ -8,6 +8,9 @@ RSpec.describe Packages::Pypi::Metadatum, type: :model do
describe 'validations' do
it { is_expected.to validate_presence_of(:package) }
+ it { is_expected.to allow_value('').for(:required_python) }
+ it { is_expected.not_to allow_value(nil).for(:required_python) }
+ it { is_expected.not_to allow_value('a' * 256).for(:required_python) }
describe '#pypi_package_type' do
it 'will not allow a package with a different package_type' do
diff --git a/spec/requests/api/pypi_packages_spec.rb b/spec/requests/api/pypi_packages_spec.rb
index fcd2d56e655..078db4f1509 100644
--- a/spec/requests/api/pypi_packages_spec.rb
+++ b/spec/requests/api/pypi_packages_spec.rb
@@ -185,6 +185,14 @@ RSpec.describe API::PypiPackages do
it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
end
+
+ context 'without requires_python' do
+ let(:token) { personal_access_token.token }
+ let(:user_headers) { basic_auth_header(user.username, token) }
+ let(:headers) { user_headers.merge(workhorse_headers) }
+
+ it_behaves_like 'PyPI package creation', :developer, :created, true
+ end
end
context 'with required_python too big' do
diff --git a/spec/services/packages/pypi/create_package_service_spec.rb b/spec/services/packages/pypi/create_package_service_spec.rb
index 3d0c10724d4..f84a77f80f7 100644
--- a/spec/services/packages/pypi/create_package_service_spec.rb
+++ b/spec/services/packages/pypi/create_package_service_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::Pypi::CreatePackageService do
+RSpec.describe Packages::Pypi::CreatePackageService, :aggregate_failures do
include PackagesManagerApiSpecHelpers
let_it_be(:project) { create(:project) }
@@ -39,6 +39,18 @@ RSpec.describe Packages::Pypi::CreatePackageService do
end
end
+ context 'without required_python' do
+ before do
+ params.delete(:requires_python)
+ end
+
+ it 'creates the package' do
+ expect { subject }.to change { Packages::Package.pypi.count }.by(1)
+
+ expect(created_package.pypi_metadatum.required_python).to eq ''
+ end
+ end
+
context 'with an invalid metadata' do
let(:requires_python) { 'x' * 256 }
@@ -73,7 +85,7 @@ RSpec.describe Packages::Pypi::CreatePackageService do
.and raise_error(/File name has already been taken/)
end
- context 'with a pending_destruction package', :aggregate_failures do
+ context 'with a pending_destruction package' do
before do
Packages::Package.pypi.last.pending_destruction!
end
diff --git a/spec/support/shared_examples/sends_git_audit_streaming_event_shared_examples.rb b/spec/support/shared_examples/sends_git_audit_streaming_event_shared_examples.rb
new file mode 100644
index 00000000000..2c2be0152a0
--- /dev/null
+++ b/spec/support/shared_examples/sends_git_audit_streaming_event_shared_examples.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'sends git audit streaming event' do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ stub_licensed_features(external_audit_events: true)
+ end
+
+ subject {}
+
+ context 'for public groups and projects' do
+ let(:group) { create(:group, :public) }
+ let(:project) { create(:project, :public, :repository, namespace: group) }
+
+ before do
+ group.external_audit_event_destinations.create!(destination_url: 'http://example.com')
+ project.add_developer(user)
+ end
+
+ context 'when user not logged in' do
+ let(:key) { create(:key) }
+
+ before do
+ if request
+ request.headers.merge! auth_env(user.username, nil, nil)
+ end
+ end
+ it 'sends the audit streaming event' do
+ expect(AuditEvents::AuditEventStreamingWorker).not_to receive(:perform_async)
+ subject
+ end
+ end
+ end
+
+ context 'for private groups and projects' do
+ let(:group) { create(:group, :private) }
+ let(:project) { create(:project, :private, :repository, namespace: group) }
+
+ before do
+ group.external_audit_event_destinations.create!(destination_url: 'http://example.com')
+ project.add_developer(user)
+ sign_in(user)
+ end
+
+ context 'when user logged in' do
+ let(:key) { create(:key, user: user) }
+
+ before do
+ if request
+ password = user.try(:password) || user.try(:token)
+ request.headers.merge! auth_env(user.username, password, nil)
+ end
+ end
+ it 'sends the audit streaming event' do
+ expect(AuditEvents::AuditEventStreamingWorker).to receive(:perform_async).once
+ subject
+ end
+ end
+ end
+end