Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-03-09 03:09:18 +00:00
parent 25096948f0
commit 276941b2c4
32 changed files with 458 additions and 71 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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?

View File

@ -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'

View File

@ -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' }

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
483f8299688a6e24fa77867b7dab8a2dad0c2b7ebe43c56c81c02ab1e0dc4674

View File

@ -0,0 +1 @@
c30b1b36ec83df1b4fdf0c3c28656b158beab4f2188875898182c2dfbd073c80

View File

@ -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);

View File

@ -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
}
```

View File

@ -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
```

View File

@ -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 \

View File

@ -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),

View File

@ -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.

View File

@ -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**.

View File

@ -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.

View File

@ -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|

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
});
});

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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