Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-08-26 15:11:58 +00:00
parent 93c1e0e4c2
commit 485728af8d
39 changed files with 167 additions and 68 deletions

View File

@ -0,0 +1 @@
# This empty file is used for agent-based integration with Kubernetes

View File

@ -109,7 +109,7 @@ export default {
v-for="template in templates"
:key="template.key"
data-qa-selector="incident_templates_item"
:is-check-item="true"
is-check-item
:is-checked="isTemplateSelected(template.key)"
@click="selectIssueTemplate(template.key)"
>

View File

@ -40,7 +40,7 @@ export default {
<gl-dropdown-item
v-for="project in projects"
:key="project.id"
:is-check-item="true"
is-check-item
:is-checked="project.id === selectedProject.id"
@click="selectProject(project)"
>

View File

@ -182,7 +182,7 @@ export default {
</template>
<template v-if="!showCustomLanguageInput" #highlighted-items>
<gl-dropdown-item :key="selectedLanguage.syntax" is-check-item :is-checked="true">
<gl-dropdown-item :key="selectedLanguage.syntax" is-check-item is-checked>
{{ selectedLanguage.label }}
</gl-dropdown-item>
</template>

View File

@ -73,8 +73,8 @@ export default {
<gl-dropdown-item
v-for="(version, index) in allVersions"
:key="version.id"
:is-check-item="true"
:is-check-centered="true"
is-check-item
is-check-centered
:is-checked="findVersionId(version.id) === currentVersionId"
:avatar-url="getAvatarUrl(version)"
@click="routeToVersion(version.id)"

View File

@ -37,7 +37,7 @@ export default {
:class="{
'is-active': version.selected,
}"
:is-check-item="true"
is-check-item
:is-checked="version.selected"
:href="version.href"
>

View File

@ -50,7 +50,7 @@ export default {
<gl-dropdown-item
v-for="mode in modeDropdownItems"
:key="mode.viewerType"
:is-check-item="true"
is-check-item
:is-checked="viewer === mode.viewerType"
@click="changeMode(mode.viewerType)"
>

View File

@ -243,7 +243,7 @@ export default {
v-for="(item, idx) in extraLinks"
:key="idx"
:href="item.url"
:is-check-item="true"
is-check-item
data-testid="milestone-combobox-extra-links"
>
{{ item.text }}

View File

@ -202,7 +202,7 @@ export default {
<gl-dropdown-item
v-for="environment in filteredEnvironments"
:key="environment.id"
:is-check-item="true"
is-check-item
:is-checked="environment.name === currentEnvironmentName"
:href="getEnvironmentPath(environment.id)"
>

View File

@ -86,7 +86,7 @@ export default {
<gl-dropdown-item
v-for="dashboard in starredDashboards"
:key="dashboard.path"
:is-check-item="true"
is-check-item
:is-checked="dashboard.path === selectedDashboardPath"
@click="selectDashboard(dashboard)"
>
@ -105,7 +105,7 @@ export default {
<gl-dropdown-item
v-for="dashboard in nonStarredDashboards"
:key="dashboard.path"
:is-check-item="true"
is-check-item
:is-checked="dashboard.path === selectedDashboardPath"
@click="selectDashboard(dashboard)"
>

View File

@ -163,7 +163,7 @@ export default {
:text="dropdownText"
>
<gl-dropdown-item
:is-check-item="true"
is-check-item
:is-checked="refreshInterval === null"
@click="removeRefreshInterval()"
>{{ __('Off') }}</gl-dropdown-item
@ -172,7 +172,7 @@ export default {
<gl-dropdown-item
v-for="(option, i) in $options.refreshIntervals"
:key="i"
:is-check-item="true"
is-check-item
:is-checked="isChecked(option)"
@click="setRefreshInterval(option)"
>{{ option.label }}</gl-dropdown-item

View File

@ -177,7 +177,7 @@ export default {
v-for="{ text, key, cls } in $options.SORT_OPTIONS"
:key="text"
:class="cls"
:is-check-item="true"
is-check-item
:is-checked="isSortDropdownItemActive(key)"
@click="fetchSortedDiscussions(key)"
>
@ -192,7 +192,7 @@ export default {
<gl-dropdown-item
v-for="filter in filters"
:key="filter.value"
:is-check-item="true"
is-check-item
:is-checked="filter.value === currentValue"
:class="{ 'is-active': filter.value === currentValue }"
:data-filter-type="filterType(filter.value)"

View File

@ -180,7 +180,7 @@ export default {
v-for="({ group_name }, index) in dailyCoverageData"
:key="index"
:value="group_name"
:is-check-item="true"
is-check-item
:is-checked="index === selectedCoverageIndex"
@click="setSelectedCoverage(index)"
>

View File

@ -237,7 +237,7 @@ export default {
v-for="branch in availableBranches"
:key="branch"
:is-checked="currentBranch === branch"
:is-check-item="true"
is-check-item
data-qa-selector="branch_menu_item_button"
@click="selectBranch(branch)"
>

View File

@ -100,7 +100,7 @@ export default {
<gl-dropdown-item
v-for="template in item"
:key="template.key"
:is-check-item="true"
is-check-item
:is-checked="
template.project_id === selectedFileTemplateProjectId &&
template.name === selectedTemplate

View File

@ -144,9 +144,9 @@ export default {
/>
<gl-dropdown-item
class="gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2! gl-mb-2"
:is-check-item="true"
is-check-item
:is-checked="isSelected($options.ANY_OPTION)"
:is-check-centered="true"
is-check-centered
@click="updateDropdown($options.ANY_OPTION)"
>
<span data-testid="item-title">{{ $options.ANY_OPTION.name }}</span>

View File

@ -53,9 +53,9 @@ export default {
<template>
<gl-dropdown-item
:is-check-item="true"
is-check-item
:is-checked="isSelected"
:is-check-centered="true"
is-check-centered
@click="$emit('change', item)"
>
<div class="gl-display-flex gl-align-items-center">

View File

@ -62,7 +62,7 @@ export default {
v-for="status in $options.STATUS_LIST"
:key="status"
data-testid="status-dropdown-item"
:is-check-item="true"
is-check-item
:is-checked="status === value"
@click="$emit('input', status)"
>

View File

@ -179,7 +179,7 @@ export default {
v-for="option in severitiesList"
:key="option.value"
data-testid="severityDropdownItem"
:is-check-item="true"
is-check-item
:is-checked="option.value === severity"
@click="updateSeverity(option.value)"
>

View File

@ -369,7 +369,7 @@ export default {
<gl-search-box-by-type ref="search" v-model="searchTerm" />
<gl-dropdown-item
:data-testid="`no-${formatIssuableAttribute.kebab}-item`"
:is-check-item="true"
is-check-item
:is-checked="isAttributeChecked($options.noAttributeId)"
@click="updateAttribute($options.noAttributeId)"
>
@ -396,7 +396,7 @@ export default {
<gl-dropdown-item
v-for="attrItem in attributesList"
:key="attrItem.id"
:is-check-item="true"
is-check-item
:is-checked="isAttributeChecked(attrItem.id)"
:data-testid="`${formatIssuableAttribute.kebab}-items`"
@click="updateAttribute(attrItem.id)"

View File

@ -77,7 +77,7 @@ export default {
<template v-for="(action, index) in actions">
<gl-dropdown-item
:key="action.key"
:is-check-item="true"
is-check-item
:is-checked="action.key === selectedAction.key"
:secondary-text="action.secondaryText"
:data-qa-selector="`${action.key}_menu_item`"

View File

@ -42,8 +42,8 @@ export default {
v-for="color in colors"
:key="color.color"
:is-checked="isColorSelected(color)"
:is-check-centered="true"
:is-check-item="true"
is-check-centered
is-check-item
@click.native.capture.stop="handleColorClick(color)"
>
<color-item :color="color.color" :title="color.title" />

View File

@ -149,8 +149,8 @@ export default {
v-for="option in presetOptions"
:key="option.id"
:is-checked="isSelected(option)"
:is-check-centered="true"
:is-check-item="true"
is-check-centered
is-check-item
@click.native.capture.stop="selectOption(option)"
>
<slot name="preset-item" :item="option">

View File

@ -369,7 +369,7 @@ export default {
<gl-dropdown-item
v-for="sortBy in sortOptions"
:key="sortBy.id"
:is-check-item="true"
is-check-item
:is-checked="sortBy.id === selectedSortOption.id"
@click="handleSortOptionClick(sortBy)"
>{{ sortBy.title }}</gl-dropdown-item

View File

@ -49,7 +49,7 @@ export default {
v-for="option in parsedOptions"
:key="option.value"
:is-checked="option.selected"
:is-check-item="true"
is-check-item
@click="setSelected(option.value)"
>
{{ option.label }}

View File

@ -253,7 +253,7 @@ export default {
<gl-dropdown-item
v-for="architecture in architectures"
:key="architecture.name"
:is-check-item="true"
is-check-item
:is-checked="selectedArchitecture === architecture.name"
data-testid="architecture-dropdown-item"
@click="selectArchitecture(architecture.name)"

View File

@ -180,7 +180,7 @@ export default {
<gl-dropdown-item
v-for="project in projects"
:key="project.id"
:is-check-item="true"
is-check-item
:is-checked="isSelectedProject(project)"
@click.stop.prevent="handleProjectSelect(project)"
>{{ project.name_with_namespace }}</gl-dropdown-item

View File

@ -154,8 +154,8 @@ export default {
v-for="(label, index) in visibleLabels"
:key="label.id"
:is-checked="isLabelSelected(label)"
:is-check-centered="true"
:is-check-item="true"
is-check-centered
is-check-item
:active="shouldHighlightFirstItem && index === 0"
active-class="is-focused"
data-testid="labels-list"

View File

@ -68,7 +68,7 @@ export default {
<template v-for="(item, itemIndex) in actionItems">
<gl-dropdown-item
:key="item.eventName"
:is-check-item="true"
is-check-item
:is-checked="selectedItem === item"
@click="changeSelectedItem(item)"
>

View File

@ -72,7 +72,7 @@ export default {
v-for="timezone in filteredResults"
:key="timezone.formattedTimezone"
:is-checked="isSelected(timezone)"
:is-check-item="true"
is-check-item
@click="selectTimezone(timezone)"
>
{{ timezone.formattedTimezone }}

View File

@ -320,7 +320,7 @@ export default {
<gl-dropdown-item
v-if="isSearchEmpty"
:is-checked="selectedIsEmpty"
:is-check-centered="true"
is-check-centered
data-testid="unassign"
@click.native.capture.stop="$emit('input', [])"
>

View File

@ -2248,6 +2248,19 @@ Returned object:
}
```
## Remove a project avatar
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92604) in GitLab 15.4.
To remove a project avatar, use a blank value for the `avatar` attribute.
Example request:
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
--data "avatar=" "https://gitlab.example.com/api/v4/projects/5"
```
## Share project with group
Allow to share project with group.

View File

@ -451,3 +451,12 @@ test-job:
reports:
dotenv: build.env
```
### Job artifacts are not expired
If some job artifacts are not expiring as expected, check if the
[**Keep artifacts from most recent successful jobs**](#keep-artifacts-from-most-recent-successful-jobs)
setting is enabled.
When this setting is enabled, job artifacts from the latest successful pipeline
of each ref do not expire and are not deleted.

View File

@ -33,6 +33,9 @@ GitLab Shell handles Git SSH sessions for GitLab and modifies the list of author
For more information, [refer to the README](https://gitlab.com/gitlab-org/gitlab-shell/-/blob/main/README.md).
for GitLab Shell.
To learn about the reasoning behind our creation of `gitlab-sshd`, read the blog post
[Why we implemented our own SSHD solution](https://about.gitlab.com/blog/2022/08/17/why-we-have-implemented-our-own-sshd-solution-on-gitlab-sass/).
## GitLab Rails
### Gitaly touch points

View File

@ -58,7 +58,7 @@ module API
optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'Deprecated: Use :topics instead'
optional :topics, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The list of topics for a project'
# TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960
optional :avatar, type: File, desc: 'Avatar image for project' # rubocop:disable Scalability/FileUploads
optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for project'
optional :printing_merge_request_link_enabled, type: Boolean, desc: 'Show link to create/view merge request when pushing from the command line'
optional :merge_method, type: String, values: %w(ff rebase_merge merge), desc: 'The merge method used when merging merge requests'
optional :suggestion_commit_message, type: String, desc: 'The commit message used to apply merge request suggestions'

View File

@ -453,6 +453,8 @@ module API
filter_attributes_using_license!(attrs)
verify_update_project_attrs!(user_project, attrs)
user_project.remove_avatar! if attrs.key?(:avatar) && attrs[:avatar].nil?
result = ::Projects::UpdateService.new(user_project, current_user, attrs).execute
if result[:status] == :success

View File

@ -48,6 +48,7 @@ end
RSpec.describe API::Projects do
include ProjectForksHelper
include WorkhorseHelpers
include StubRequests
let_it_be(:user) { create(:user) }
@ -1349,7 +1350,12 @@ RSpec.describe API::Projects do
it 'uploads avatar for project a project' do
project = attributes_for(:project, avatar: fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif'))
post api('/projects', user), params: project
workhorse_form_with_file(
api('/projects', user),
method: :post,
file_key: :avatar,
params: project
)
project_id = json_response['id']
expect(json_response['avatar_url']).to eq("http://localhost/uploads/-/system/project/avatar/#{project_id}/banana_sample.gif")
@ -1925,8 +1931,6 @@ RSpec.describe API::Projects do
end
describe "POST /projects/:id/uploads/authorize" do
include WorkhorseHelpers
let(:headers) { workhorse_internal_api_request_header.merge({ 'HTTP_GITLAB_WORKHORSE' => 1 }) }
context 'with authorized user' do
@ -3584,18 +3588,77 @@ RSpec.describe API::Projects do
end
end
it 'updates avatar' do
project_param = {
avatar: fixture_file_upload('spec/fixtures/banana_sample.gif',
'image/gif')
}
context 'with changes to the avatar' do
let_it_be(:avatar_file) { fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') }
let_it_be(:alternate_avatar_file) { fixture_file_upload('spec/fixtures/rails_sample.png', 'image/png') }
let_it_be(:project_with_avatar, reload: true) do
create(:project,
:private,
:repository,
name: 'project-with-avatar',
creator_id: user.id,
namespace: user.namespace,
avatar: avatar_file)
end
put api("/projects/#{project3.id}", user), params: project_param
it 'uploads avatar to project without an avatar' do
workhorse_form_with_file(
api("/projects/#{project3.id}", user),
method: :put,
file_key: :avatar,
params: { avatar: avatar_file }
)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['avatar_url']).to eq('http://localhost/uploads/'\
'-/system/project/avatar/'\
"#{project3.id}/banana_sample.gif")
aggregate_failures "testing response" do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['avatar_url']).to eq('http://localhost/uploads/'\
'-/system/project/avatar/'\
"#{project3.id}/banana_sample.gif")
end
end
it 'uploads and changes avatar to project with an avatar' do
workhorse_form_with_file(
api("/projects/#{project_with_avatar.id}", user),
method: :put,
file_key: :avatar,
params: { avatar: alternate_avatar_file }
)
aggregate_failures "testing response" do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['avatar_url']).to eq('http://localhost/uploads/'\
'-/system/project/avatar/'\
"#{project_with_avatar.id}/rails_sample.png")
end
end
it 'uploads and changes avatar to project among other changes' do
workhorse_form_with_file(
api("/projects/#{project_with_avatar.id}", user),
method: :put,
file_key: :avatar,
params: { description: 'changed description', avatar: avatar_file }
)
aggregate_failures "testing response" do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['description']).to eq('changed description')
expect(json_response['avatar_url']).to eq('http://localhost/uploads/'\
'-/system/project/avatar/'\
"#{project_with_avatar.id}/banana_sample.gif")
end
end
it 'removes avatar from project with an avatar' do
put api("/projects/#{project_with_avatar.id}", user), params: { avatar: '' }
aggregate_failures "testing response" do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['avatar_url']).to be_nil
expect(project_with_avatar.reload.avatar_url).to be_nil
end
end
end
it 'updates auto_devops_deploy_strategy' do

View File

@ -51,7 +51,7 @@ const (
gitProjectPattern = `^/.+\.git/`
geoGitProjectPattern = `^/[^-].+\.git/` // Prevent matching routes like /-/push_from_secondary
projectPattern = `^/([^/]+/){1,}[^/]+/`
apiProjectPattern = apiPattern + `v4/projects/[^/]+/` // API: Projects can be encoded via group%2Fsubgroup%2Fproject
apiProjectPattern = apiPattern + `v4/projects/[^/]+` // API: Projects can be encoded via group%2Fsubgroup%2Fproject
apiTopicPattern = apiPattern + `v4/topics`
snippetUploadPattern = `^/uploads/personal_snippet`
userUploadPattern = `^/uploads/user`
@ -269,40 +269,40 @@ func configureRoutes(u *upstream) {
// https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56731.
// Maven Artifact Repository
u.route("PUT", apiProjectPattern+`packages/maven/`, requestBodyUploader),
u.route("PUT", apiProjectPattern+`/packages/maven/`, requestBodyUploader),
// Conan Artifact Repository
u.route("PUT", apiPattern+`v4/packages/conan/`, requestBodyUploader),
u.route("PUT", apiProjectPattern+`packages/conan/`, requestBodyUploader),
u.route("PUT", apiProjectPattern+`/packages/conan/`, requestBodyUploader),
// Generic Packages Repository
u.route("PUT", apiProjectPattern+`packages/generic/`, requestBodyUploader),
u.route("PUT", apiProjectPattern+`/packages/generic/`, requestBodyUploader),
// NuGet Artifact Repository
u.route("PUT", apiProjectPattern+`packages/nuget/`, mimeMultipartUploader),
u.route("PUT", apiProjectPattern+`/packages/nuget/`, mimeMultipartUploader),
// PyPI Artifact Repository
u.route("POST", apiProjectPattern+`packages/pypi`, mimeMultipartUploader),
u.route("POST", apiProjectPattern+`/packages/pypi`, mimeMultipartUploader),
// Debian Artifact Repository
u.route("PUT", apiProjectPattern+`packages/debian/`, requestBodyUploader),
u.route("PUT", apiProjectPattern+`/packages/debian/`, requestBodyUploader),
// RPM Artifact Repository
u.route("POST", apiProjectPattern+`packages/rpm/`, requestBodyUploader),
// Gem Artifact Repository
u.route("POST", apiProjectPattern+`packages/rubygems/`, requestBodyUploader),
u.route("POST", apiProjectPattern+`/packages/rubygems/`, requestBodyUploader),
// Terraform Module Package Repository
u.route("PUT", apiProjectPattern+`packages/terraform/modules/`, requestBodyUploader),
u.route("PUT", apiProjectPattern+`/packages/terraform/modules/`, requestBodyUploader),
// Helm Artifact Repository
u.route("POST", apiProjectPattern+`packages/helm/api/[^/]+/charts\z`, mimeMultipartUploader),
u.route("POST", apiProjectPattern+`/packages/helm/api/[^/]+/charts\z`, mimeMultipartUploader),
// We are porting API to disk acceleration
// we need to declare each routes until we have fixed all the routes on the rails codebase.
// Overall status can be seen at https://gitlab.com/groups/gitlab-org/-/epics/1802#current-status
u.route("POST", apiProjectPattern+`wikis/attachments\z`, tempfileMultipartProxy),
u.route("POST", apiProjectPattern+`/wikis/attachments\z`, tempfileMultipartProxy),
u.route("POST", apiPattern+`graphql\z`, tempfileMultipartProxy),
u.route("POST", apiTopicPattern, tempfileMultipartProxy),
u.route("PUT", apiTopicPattern, tempfileMultipartProxy),
@ -315,16 +315,20 @@ func configureRoutes(u *upstream) {
u.route("POST", importPattern+`gitlab_group`, mimeMultipartUploader),
// Issuable Metric image upload
u.route("POST", apiProjectPattern+`issues/[0-9]+/metric_images\z`, mimeMultipartUploader),
u.route("POST", apiProjectPattern+`/issues/[0-9]+/metric_images\z`, mimeMultipartUploader),
// Alert Metric image upload
u.route("POST", apiProjectPattern+`alert_management_alerts/[0-9]+/metric_images\z`, mimeMultipartUploader),
u.route("POST", apiProjectPattern+`/alert_management_alerts/[0-9]+/metric_images\z`, mimeMultipartUploader),
// Requirements Import via UI upload acceleration
u.route("POST", projectPattern+`requirements_management/requirements/import_csv`, mimeMultipartUploader),
// Uploads via API
u.route("POST", apiProjectPattern+`uploads\z`, mimeMultipartUploader),
u.route("POST", apiProjectPattern+`/uploads\z`, mimeMultipartUploader),
// Project Avatar
u.route("POST", apiPattern+`v4/projects\z`, tempfileMultipartProxy),
u.route("PUT", apiProjectPattern+`\z`, tempfileMultipartProxy),
// Explicitly proxy API requests
u.route("", apiPattern, proxy),

View File

@ -122,6 +122,10 @@ func TestAcceleratedUpload(t *testing.T) {
{"POST", `/example`, false},
{"POST", `/uploads/personal_snippet`, true},
{"POST", `/uploads/user`, true},
{"POST", `/api/v4/projects`, false},
{"PUT", `/api/v4/projects/group%2Fproject`, false},
{"PUT", `/api/v4/projects/group%2Fsubgroup%2Fproject`, false},
{"PUT", `/api/v4/projects/39`, false},
{"POST", `/api/v4/projects/1/uploads`, true},
{"POST", `/api/v4/projects/group%2Fproject/uploads`, true},
{"POST", `/api/v4/projects/group%2Fsubgroup%2Fproject/uploads`, true},