Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-02-18 12:15:31 +00:00
parent 6c744c5ac9
commit 6de2a04a4e
54 changed files with 440 additions and 412 deletions

View file

@ -1,19 +1,10 @@
<script>
import { GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
i18n: {
edit: __('Edit'),
webIde: __('Web IDE'),
},
components: {
GlButton,
WebIdeLink,
},
mixins: [glFeatureFlagsMixin()],
props: {
showEditButton: {
type: Boolean,
@ -43,7 +34,6 @@ export default {
<template>
<web-ide-link
v-if="glFeatures.consolidatedEditButton"
:show-edit-button="showEditButton"
class="gl-mr-3"
:edit-url="editPath"
@ -53,26 +43,4 @@ export default {
disable-fork-modal
@edit="onEdit"
/>
<div v-else>
<gl-button
v-if="showEditButton"
class="gl-mr-2"
category="primary"
variant="confirm"
data-testid="edit"
@click="onEdit('simple')"
>
{{ $options.i18n.edit }}
</gl-button>
<gl-button
class="gl-mr-3"
category="primary"
variant="confirm"
data-testid="web-ide"
@click="onEdit('ide')"
>
{{ $options.i18n.webIde }}
</gl-button>
</div>
</template>

View file

@ -187,6 +187,7 @@ export default {
deep: true,
handler() {
// TODO Implement back button response using onpopstate
// See: https://gitlab.com/gitlab-org/gitlab/-/issues/333804
updateHistory({
url: fromSearchToUrl(this.search),
title: document.title,

View file

@ -91,8 +91,8 @@ export const ACCESS_LEVEL_REF_PROTECTED = 'REF_PROTECTED';
// CiRunnerSort
export const CREATED_DESC = 'CREATED_DESC';
export const CREATED_ASC = 'CREATED_ASC'; // TODO Add this to the API
export const CONTACTED_DESC = 'CONTACTED_DESC'; // TODO Add this to the API
export const CREATED_ASC = 'CREATED_ASC';
export const CONTACTED_DESC = 'CONTACTED_DESC';
export const CONTACTED_ASC = 'CONTACTED_ASC';
export const DEFAULT_SORT = CREATED_DESC;

View file

@ -190,6 +190,7 @@ export default {
deep: true,
handler() {
// TODO Implement back button reponse using onpopstate
// See https://gitlab.com/gitlab-org/gitlab/-/issues/333804
updateHistory({
url: fromSearchToUrl(this.search),
title: document.title,

View file

@ -45,7 +45,6 @@ class Projects::BlobController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml)
push_frontend_feature_flag(:highlight_js, @project, default_enabled: :yaml)
push_frontend_feature_flag(:consolidated_edit_button, @project, default_enabled: :yaml)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
end

View file

@ -22,7 +22,6 @@ class Projects::TreeController < Projects::ApplicationController
push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml)
push_frontend_feature_flag(:highlight_js, @project, default_enabled: :yaml)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
push_frontend_feature_flag(:consolidated_edit_button, @project, default_enabled: :yaml)
end
feature_category :source_code_management

View file

@ -41,7 +41,6 @@ class ProjectsController < Projects::ApplicationController
push_frontend_feature_flag(:increase_page_size_exponentially, @project, default_enabled: :yaml)
push_frontend_feature_flag(:new_dir_modal, @project, default_enabled: :yaml)
push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks)
push_frontend_feature_flag(:consolidated_edit_button, @project, default_enabled: :yaml)
push_frontend_feature_flag(:work_items, @project, default_enabled: :yaml)
end

View file

@ -15,8 +15,19 @@ module Types
max_page_size: 20,
resolver: Resolvers::ContainerRepositoryTagsResolver
field :size,
GraphQL::Types::Float,
null: true,
description: 'Deduplicated size of the image repository in bytes. This is only available on GitLab.com for repositories created after `2021-11-04`.'
def can_delete
Ability.allowed?(current_user, :destroy_container_image, object)
end
def size
object.size
rescue Faraday::Error
raise ::Gitlab::Graphql::Errors::ResourceNotAvailable, "Can't connect to the Container Registry. If this error persists, please review the troubleshooting documentation."
end
end
end

View file

@ -14,6 +14,8 @@ class ContainerRepository < ApplicationRecord
ABORTABLE_MIGRATION_STATES = (ACTIVE_MIGRATION_STATES + %w[pre_import_done default]).freeze
MIGRATION_STATES = (IDLE_MIGRATION_STATES + ACTIVE_MIGRATION_STATES).freeze
MIGRATION_PHASE_1_STARTED_AT = Date.new(2021, 11, 4).freeze
TooManyImportsError = Class.new(StandardError)
NativeImportError = Class.new(StandardError)
@ -408,6 +410,16 @@ class ContainerRepository < ApplicationRecord
update!(expiration_policy_started_at: Time.zone.now)
end
def size
strong_memoize(:size) do
next unless Gitlab.com?
next if self.created_at.before?(MIGRATION_PHASE_1_STARTED_AT)
next unless gitlab_api_client.supports_gitlab_api?
gitlab_api_client.repository_details(self.path, with_size: true)['size_bytes']
end
end
def migration_in_active_state?
migration_state.in?(ACTIVE_MIGRATION_STATES)
end

View file

@ -9,6 +9,9 @@ class Integration < ApplicationRecord
include Integrations::HasDataFields
include FromUnion
include EachBatch
include IgnorableColumns
ignore_column :template, remove_with: '14.10', remove_after: '2022-03-22'
INTEGRATION_NAMES = %w[
asana assembla bamboo bugzilla buildkite campfire confluence custom_issue_tracker datadog discord

View file

@ -145,7 +145,7 @@ module Integrations
end
def one_issue_tracker
return if template? || instance?
return if instance?
return if project.blank?
if project.integrations.external_issue_trackers.where.not(id: id).any?

View file

@ -115,7 +115,6 @@ module Integrations
end
def prometheus_available?
return false if template?
return false unless project
project.all_clusters.enabled.eager_load(:integration_prometheus).any? do |cluster|

View file

@ -73,3 +73,5 @@ class DeploymentEntity < Grape::Entity
request.try(:project) || options[:project]
end
end
DeploymentEntity.prepend_mod

View file

@ -20,6 +20,7 @@ class EnvironmentEntity < Grape::Entity
expose :last_deployment, using: DeploymentEntity
expose :stop_action_available?, as: :has_stop_action
expose :rollout_status, if: -> (*) { can_read_deploy_board? }, using: RolloutStatusEntity
expose :tier
expose :upcoming_deployment, if: -> (environment) { environment.upcoming_deployment } do |environment, ops|
DeploymentEntity.represent(environment.upcoming_deployment,

View file

@ -32,12 +32,8 @@ class BulkCreateIntegrationService
end
def integration_hash
if integration.template?
integration.to_integration_hash
else
integration.to_integration_hash.tap { |json| json['inherit_from_id'] = integration.inherit_from_id || integration.id }
end
end
def data_fields_hash
integration.to_data_fields_hash

View file

@ -1,10 +0,0 @@
# frozen_string_literal: true
module Integrations
# TODO: Remove this as part of https://gitlab.com/gitlab-org/gitlab/-/issues/335178
class PropagateTemplateService
def self.propagate(_integration)
# no-op
end
end
end

View file

@ -5,11 +5,7 @@
.file-actions.gl-display-flex.gl-align-items-center.gl-flex-wrap.gl-md-justify-content-end<
= render 'projects/blob/viewer_switcher', blob: blob unless blame
- if Feature.enabled?(:consolidated_edit_button, @project)
= render 'shared/web_ide_button', blob: blob
- else
= edit_blob_button(@project, @ref, @path, blob: blob)
= ide_edit_button(@project, @ref, @path, blob: blob)
- if can_view_pipeline_editor?(@project) && @path == @project.ci_config_path_or_default
= link_to "Pipeline Editor", project_ci_pipeline_editor_path(@project, branch_name: @ref), class: "btn gl-button btn-confirm-secondary gl-ml-3"
.btn-group{ role: "group", class: ("gl-ml-3" if current_user) }>

View file

@ -1,8 +0,0 @@
---
name: consolidated_edit_button
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44311
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/270433
milestone: '13.5'
type: development
group: group::editor
default_enabled: false

View file

@ -1,8 +0,0 @@
---
name: generic_packages
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40045
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/239133
milestone: '13.4'
type: development
group: group::release
default_enabled: true

View file

@ -210,10 +210,11 @@ GET /registry/repositories/:id
| `id` | integer/string | yes | The ID of the registry repository accessible by the authenticated user. |
| `tags` | boolean | no | If the parameter is included as `true`, the response includes an array of `"tags"`. |
| `tags_count` | boolean | no | If the parameter is included as `true`, the response includes `"tags_count"`. |
| `size` | boolean | no | If the parameter is included as `true`, the response includes `"size"`. This is the deduplicated size of all images within the repository. Deduplication eliminates extra copies of identical data. For example, if you upload the same image twice, the Container Registry stores only one copy. This field is only available on GitLab.com for repositories created after `2021-11-04`. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/registry/repositories/2?tags=true&tags_count=true"
"https://gitlab.example.com/api/v4/registry/repositories/2?tags=true&tags_count=true&size=true"
```
Example response:
@ -234,7 +235,8 @@ Example response:
"path": "group/project:0.0.1",
"location": "gitlab.example.com:5000/group/project:0.0.1"
}
]
],
"size": 2818413
}
```

View file

@ -9577,6 +9577,7 @@ Details of a container repository.
| <a id="containerrepositorydetailsname"></a>`name` | [`String!`](#string) | Name of the container repository. |
| <a id="containerrepositorydetailspath"></a>`path` | [`String!`](#string) | Path of the container repository. |
| <a id="containerrepositorydetailsproject"></a>`project` | [`Project!`](#project) | Project of the container registry. |
| <a id="containerrepositorydetailssize"></a>`size` | [`Float`](#float) | Deduplicated size of the image repository in bytes. This is only available on GitLab.com for repositories created after `2021-11-04`. |
| <a id="containerrepositorydetailsstatus"></a>`status` | [`ContainerRepositoryStatus`](#containerrepositorystatus) | Status of the container repository. |
| <a id="containerrepositorydetailstagscount"></a>`tagsCount` | [`Int!`](#int) | Number of tags associated with this image. |
| <a id="containerrepositorydetailsupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp when the container repository was updated. |

View file

@ -6,12 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab Generic Packages Repository **(FREE)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4209) in GitLab 13.5.
> - It's [deployed behind a feature flag](../../../user/feature_flags.md), enabled by default.
> - It's enabled on GitLab.com.
> - It's able to be enabled or disabled per-project.
> - It's recommended for production use.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-generic-packages-in-the-package-registry).
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4209) in GitLab 13.5 [with a flag](../../../administration/feature_flags.md) named `generic_packages`. Enabled by default.
> - Generally available in GitLab 14.8. [Feature flag `generic_packages`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80886) removed.
Publish generic files, like release binaries, in your project's Package Registry. Then, install the packages whenever you need to use them as a dependency.
@ -194,31 +190,6 @@ upload:
- Invoke-RestMethod -Headers @{ "JOB-TOKEN"="$CI_JOB_TOKEN" } -InFile path/to/file.txt -uri "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/0.0.1/file.txt" -Method put
```
### Enable or disable generic packages in the Package Registry
Support for generic packages is under development but ready for production use.
It is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can opt to disable it.
To enable it:
```ruby
# For the instance
Feature.enable(:generic_packages)
# For a single project
Feature.enable(:generic_packages, Project.find(<project id>))
```
To disable it:
```ruby
# For the instance
Feature.disable(:generic_packages)
# For a single project
Feature.disable(:generic_packages, Project.find(<project id>))
```
### Generic package sample project
The [Write CI-CD Variables in Pipeline](https://gitlab.com/guided-explorations/cfg-data/write-ci-cd-variables-in-pipeline) project contains a working example you can use to create, upload, and download generic packages in GitLab CI/CD.

View file

@ -68,7 +68,7 @@ threads. Some quick actions might not be available to all subscription tiers.
| `/done` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Mark to do as done. |
| `/draft` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Toggle the draft status. |
| `/due <date>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set due date. Examples of valid `<date>` include `in 2 days`, `this Friday` and `December 31st`. |
| `/duplicate <#issue>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Close this issue and mark as a duplicate of another issue. **(FREE)** Also, mark both as related. |
| `/duplicate <#issue>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Close this issue and mark as a duplicate of another issue. Also, mark both as related. |
| `/epic <epic>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add to epic `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic. |
| `/estimate <time>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Set time estimate. For example, `/estimate 1mo 2w 3d 4h 5m`. Learn more about [time tracking](time_tracking.md). |
| `/health_status <value>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set [health status](issues/managing_issues.md#health-status). Valid options for `<value>` are `on_track`, `needs_attention`, and `at_risk` ([introduced in GitLab 14.7](https://gitlab.com/gitlab-org/gitlab/-/issues/213814)). |

View file

@ -23,11 +23,17 @@ module API
params do
optional :tags, type: Boolean, default: false, desc: 'Determines if tags should be included'
optional :tags_count, type: Boolean, default: false, desc: 'Determines if the tags count should be included'
optional :size, type: Boolean, default: false, desc: 'Determines if the size should be included'
end
get ':id' do
authorize!(:read_container_image, repository)
present repository, with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count], user: current_user
present repository,
with: Entities::ContainerRegistry::Repository,
tags: params[:tags],
tags_count: params[:tags_count],
size: params[:size],
user: current_user
end
end
end

View file

@ -22,6 +22,7 @@ module API
expose :tags_count, if: -> (_, options) { options[:tags_count] }
expose :tags, using: Tag, if: -> (_, options) { options[:tags] }
expose :delete_api_path, if: ->(object, options) { Ability.allowed?(options[:user], :admin_container_image, object) }
expose :size, if: -> (_, options) { options[:size] }
private

View file

@ -14,8 +14,6 @@ module API
before do
require_packages_enabled!
authenticate_non_get!
require_generic_packages_available!
end
params do
@ -113,10 +111,6 @@ module API
include ::API::Helpers::PackagesHelpers
include ::API::Helpers::Packages::BasicAuthHelpers
def require_generic_packages_available!
not_found! unless Feature.enabled?(:generic_packages, project, default_enabled: true)
end
def project
authorized_user_project
end

View file

@ -31,10 +31,12 @@ module ContainerRegistry
registry_features = Gitlab::CurrentSettings.container_registry_features || []
next true if ::Gitlab.com? && registry_features.include?(REGISTRY_GITLAB_V1_API_FEATURE)
response = faraday.get('/gitlab/v1/')
with_token_faraday do |faraday_client|
response = faraday_client.get('/gitlab/v1/')
response.success? || response.status == 401
end
end
end
# https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/api.md#import-repository
def pre_import_repository(path)
@ -50,17 +52,48 @@ module ContainerRegistry
# https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/api.md#get-repository-import-status
def import_status(path)
body_hash = response_body(faraday.get(import_url_for(path)))
with_import_token_faraday do |faraday_client|
body_hash = response_body(faraday_client.get(import_url_for(path)))
body_hash['status'] || 'error'
end
end
def repository_details(path, with_size: false)
with_token_faraday do |faraday_client|
req = faraday_client.get("/gitlab/v1/repositories/#{path}/") do |req|
req.params['size'] = 'self' if with_size
end
break {} unless req.success?
response_body(req)
end
end
private
def start_import_for(path, pre:)
faraday.put(import_url_for(path)) do |req|
with_import_token_faraday do |faraday_client|
faraday_client.put(import_url_for(path)) do |req|
req.params['pre'] = pre.to_s
end
end
end
def with_token_faraday
yield faraday
end
def with_import_token_faraday
yield faraday_with_import_token
end
def faraday_with_import_token(timeout_enabled: true)
@faraday_with_import_token ||= faraday_base(timeout_enabled: timeout_enabled) do |conn|
# initialize the connection with the :import_token instead of :token
initialize_connection(conn, @options.merge(token: @options[:import_token]), &method(:configure_connection))
end
end
def import_url_for(path)
"/gitlab/v1/import/#{path}/"

View file

@ -2,26 +2,16 @@
module ContainerRegistry
class Registry
include Gitlab::Utils::StrongMemoize
attr_reader :uri, :client, :path
attr_reader :uri, :client, :gitlab_api_client, :path
def initialize(uri, options = {})
@uri = uri
@options = options
@path = @options[:path] || default_path
@client = ContainerRegistry::Client.new(@uri, @options)
end
def gitlab_api_client
strong_memoize(:gitlab_api_client) do
token = Auth::ContainerRegistryAuthenticationService.import_access_token
url = Gitlab.config.registry.api_url
host_port = Gitlab.config.registry.host_port
ContainerRegistry::GitlabApiClient.new(url, token: token, path: host_port)
end
import_token = Auth::ContainerRegistryAuthenticationService.import_access_token
@gitlab_api_client = ContainerRegistry::GitlabApiClient.new(@uri, @options.merge(import_token: import_token))
end
private

View file

@ -11076,6 +11076,9 @@ msgstr ""
msgid "DastProfiles|Branch missing"
msgstr ""
msgid "DastProfiles|Choose a scan method"
msgstr ""
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@ -11217,6 +11220,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
msgid "DastProfiles|Scan method"
msgstr ""
msgid "DastProfiles|Scan mode"
msgstr ""
@ -11295,12 +11301,24 @@ msgstr ""
msgid "DastProfiles|Website"
msgstr ""
msgid "DastProfiles|What does each method do?"
msgstr ""
msgid "DastProfiles|You can either choose a passive scan or validate the target site from the site profile management page. %{docsLinkStart}Learn more about site validation.%{docsLinkEnd}"
msgstr ""
msgid "DastProfiles|You cannot run an active scan against an unvalidated site."
msgstr ""
msgid "DastProfiles|folder/dast_example.har or https://example.com/dast_example.har"
msgstr ""
msgid "DastProfiles|folder/example.postman_collection.json or https://example.com/"
msgstr ""
msgid "DastProfiles|folder/openapi.json or https://example.com/openapi.json"
msgstr ""
msgid "DastSiteValidation|Copy HTTP header to clipboard"
msgstr ""
@ -17839,6 +17857,9 @@ msgstr ""
msgid "HAR file path or URL"
msgstr ""
msgid "HTTP Archive (HAR)"
msgstr ""
msgid "HTTP Basic: Access denied\\nYou must use a personal access token with 'api' scope for Git over HTTP.\\nYou can generate one at %{profile_personal_access_tokens_url}"
msgstr ""

View file

@ -32,7 +32,6 @@
"qa/specs/features/ee/browser_ui/10_protect/policy_alerts_list_spec.rb": 14.055217947000074,
"qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb": 14.212461153999811,
"qa/specs/features/ee/api/2_plan/epics_milestone_dates_spec.rb": 14.218627059000028,
"qa/specs/features/browser_ui/1_manage/group/transfer_group_spec.rb": 14.295524570999987,
"qa/specs/features/api/1_manage/project_access_token_spec.rb": 14.394589879999785,
"qa/specs/features/ee/browser_ui/2_plan/multiple_assignees_for_issues/four_assignees_spec.rb": 14.505683429000328,
"qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb": 14.804579386000114,

View file

@ -33,16 +33,11 @@ module QA
end
def click_edit
# TODO: remove this condition and else part once ff :consolidated_edit_button is enabled by default
if has_element?(:action_dropdown)
within_element(:action_dropdown) do
click_button(class: 'dropdown-toggle-split')
click_element(:edit_menu_item)
click_element(:edit_button)
end
else
click_on 'Edit'
end
end
def click_delete

View file

@ -102,16 +102,6 @@ module QA
click_element(:save_permissions_changes_button)
end
def transfer_group(target_group, source_group)
expand_content :advanced_settings_content
select_namespace(target_group)
click_element(:transfer_button)
fill_confirmation_text(source_group)
confirm_transfer
end
end
end
end

View file

@ -1,51 +0,0 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Manage' do
describe 'Subgroup transfer' do
let(:source_group) do
Resource::Group.fabricate_via_api! do |group|
group.path = "source-group-for-transfer_#{SecureRandom.hex(8)}"
end
end
let!(:target_group) do
Resource::Group.fabricate_via_api! do |group|
group.path = "target-group-for-transfer_#{SecureRandom.hex(8)}"
end
end
let(:sub_group_for_transfer) do
Resource::Group.fabricate_via_api! do |group|
group.path = "subgroup-for-transfer_#{SecureRandom.hex(8)}"
group.sandbox = source_group
end
end
before do
Flow::Login.sign_in
sub_group_for_transfer.visit!
end
it 'transfers a subgroup to another group',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347692' do
Page::Group::Menu.perform(&:click_group_general_settings_item)
Page::Group::Settings::General.perform do |general|
general.transfer_group(target_group.path, sub_group_for_transfer.path)
sub_group_for_transfer.sandbox = target_group
sub_group_for_transfer.reload!
end
expect(page).to have_text("Group '#{sub_group_for_transfer.path}' was successfully transferred.")
expect(page.driver.current_url).to include(sub_group_for_transfer.full_path)
end
after do
source_group&.remove_via_api!
target_group&.remove_via_api!
sub_group_for_transfer&.remove_via_api!
end
end
end
end

View file

@ -217,11 +217,6 @@ FactoryBot.define do
end
end
trait :template do
project { nil }
template { true }
end
trait :group do
group
project { nil }

View file

@ -154,34 +154,52 @@ RSpec.describe 'Edit group settings' do
namespace_select.find('button').click
namespace_select.find('.dropdown-menu p', text: target_group_name, match: :first).click
click_button "Transfer group"
click_button 'Transfer group'
end
page.within(confirm_modal) do
expect(page).to have_text "You are going to transfer #{selected_group.name} to another namespace. Are you ABSOLUTELY sure?"
fill_in "confirm_name_input", with: selected_group.name
click_button "Confirm"
fill_in 'confirm_name_input', with: selected_group.name
click_button 'Confirm'
end
expect(page).to have_text "Group '#{selected_group.name}' was successfully transferred."
expect(current_url).to include(selected_group.reload.full_path)
end
end
context 'with a sub group' do
context 'from a subgroup' do
let(:selected_group) { create(:group, path: 'foo-subgroup', parent: group) }
let(:target_group_name) { "No parent group" }
context 'to no parent group' do
let(:target_group_name) { 'No parent group' }
it_behaves_like 'can transfer the group'
end
context 'with a root group' do
context 'to a different parent group' do
let(:target_group) { create(:group, path: 'foo-parentgroup') }
let(:target_group_name) { target_group.name }
before do
target_group.add_owner(user)
end
it_behaves_like 'can transfer the group'
end
end
context 'from a root group' do
let(:selected_group) { create(:group, path: 'foo-rootgroup') }
context 'to a parent group' do
let(:target_group_name) { group.name }
it_behaves_like 'can transfer the group'
end
end
end
context 'disable email notifications' do
it 'is visible' do

View file

@ -75,22 +75,5 @@ RSpec.describe 'Projects > Files > User browses LFS files' do
expect(page).to have_selector(:link_or_button, 'Edit in Web IDE')
end
end
context 'when feature flag :consolidated_edit_button is off' do
before do
stub_feature_flags(consolidated_edit_button: false)
click_link('files')
click_link('lfs')
click_link('lfs_object.iso')
end
it 'does not show single file edit link' do
page.within('.content') do
expect(page).to have_selector(:link_or_button, 'Web IDE')
expect(page).not_to have_css('button[data-testid="edit"')
end
end
end
end
end

View file

@ -236,116 +236,5 @@ RSpec.describe 'Projects > Files > User edits files', :js do
let(:project) { project2 }
end
end
context 'when feature flag :consolidated_edit_button is off' do
before do
stub_feature_flags(consolidated_edit_button: false)
end
context 'when an user does not have write access', :js do
before do
project2.add_reporter(user)
visit(project2_tree_path_root_ref)
wait_for_requests
end
it 'inserts a content of a file in a forked project', :sidekiq_might_not_need_inline do
set_default_button('edit')
click_link('.gitignore')
click_link_or_button('Edit')
expect_fork_prompt
click_link_or_button('Fork')
expect_fork_status
find('.file-editor', match: :first)
find('#editor')
set_editor_value('*.rbca')
expect(editor_value).to eq('*.rbca')
end
it 'opens the Web IDE in a forked project', :sidekiq_might_not_need_inline do
set_default_button('webide')
click_link('.gitignore')
click_link_or_button('Web IDE')
expect_fork_prompt
click_link_or_button('Fork')
expect_fork_status
expect(page).to have_css('.ide-sidebar-project-title', text: "#{project2.name} #{user.namespace.full_path}/#{project2.path}")
expect(page).to have_css('.ide .multi-file-tab', text: '.gitignore')
end
it 'commits an edited file in a forked project', :sidekiq_might_not_need_inline do
set_default_button('edit')
click_link('.gitignore')
click_link_or_button('Edit')
expect_fork_prompt
click_link_or_button('Fork')
expect_fork_status
find('.file-editor', match: :first)
find('#editor')
set_editor_value('*.rbca')
fill_in(:commit_message, with: 'New commit message', visible: true)
click_button('Commit changes')
fork = user.fork_of(project2.reload)
expect(current_path).to eq(project_new_merge_request_path(fork))
wait_for_requests
expect(page).to have_content('New commit message')
end
context 'when the user already had a fork of the project', :js do
let!(:forked_project) { fork_project(project2, user, namespace: user.namespace, repository: true) }
before do
visit(project2_tree_path_root_ref)
wait_for_requests
end
it 'links to the forked project for editing', :sidekiq_might_not_need_inline do
set_default_button('edit')
click_link('.gitignore')
click_link_or_button('Edit')
expect(page).not_to have_link('Fork')
find('#editor')
set_editor_value('*.rbca')
fill_in(:commit_message, with: 'Another commit', visible: true)
click_button('Commit changes')
fork = user.fork_of(project2)
expect(current_path).to eq(project_new_merge_request_path(fork))
wait_for_requests
expect(page).to have_content('Another commit')
expect(page).to have_content("From #{forked_project.full_path}")
expect(page).to have_content("into #{project2.full_path}")
end
it_behaves_like 'unavailable for an archived project' do
let(:project) { project2 }
end
end
end
end
end
end

View file

@ -64,6 +64,5 @@
"items": { "$ref": "job/job.json" }
},
"status": { "type": "string" }
},
"additionalProperties": false
}
}

View file

@ -35,6 +35,8 @@
"auto_stop_at": { "type": "string", "format": "date-time" },
"can_stop": { "type": "boolean" },
"has_opened_alert": { "type": "boolean" },
"tier": { "type": "string" },
"required_approval_count": { "type": "integer" },
"cluster_type": { "type": "types/nullable_string.json" },
"terminal_path": { "type": "types/nullable_string.json" },
"rollout_status": {

View file

@ -1,4 +1,3 @@
import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import BlobEdit from '~/repository/components/blob_edit.vue';
import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
@ -13,17 +12,12 @@ const DEFAULT_PROPS = {
describe('BlobEdit component', () => {
let wrapper;
const createComponent = (consolidatedEditButton = false, props = {}) => {
const createComponent = (props = {}) => {
wrapper = shallowMount(BlobEdit, {
propsData: {
...DEFAULT_PROPS,
...props,
},
provide: {
glFeatures: {
consolidatedEditButton,
},
},
});
};
@ -32,9 +26,7 @@ describe('BlobEdit component', () => {
wrapper = null;
});
const findButtons = () => wrapper.findAll(GlButton);
const findEditButton = () => wrapper.find('[data-testid="edit"]');
const findWebIdeButton = () => wrapper.find('[data-testid="web-ide"]');
const findWebIdeLink = () => wrapper.find(WebIdeLink);
it('renders component', () => {
@ -48,28 +40,8 @@ describe('BlobEdit component', () => {
});
});
it('renders both buttons', () => {
createComponent();
expect(findButtons()).toHaveLength(2);
});
it('renders the Edit button', () => {
createComponent();
expect(findEditButton().text()).toBe('Edit');
expect(findEditButton()).not.toBeDisabled();
});
it('renders the Web IDE button', () => {
createComponent();
expect(findWebIdeButton().text()).toBe('Web IDE');
expect(findWebIdeButton()).not.toBeDisabled();
});
it('renders WebIdeLink component', () => {
createComponent(true);
createComponent();
const { editPath: editUrl, webIdePath: webIdeUrl, needsToFork } = DEFAULT_PROPS;
@ -86,13 +58,13 @@ describe('BlobEdit component', () => {
const showEditButton = false;
it('renders WebIdeLink component without an edit button', () => {
createComponent(true, { showEditButton });
createComponent({ showEditButton });
expect(findWebIdeLink().props()).toMatchObject({ showEditButton });
});
it('does not render an Edit button', () => {
createComponent(false, { showEditButton });
createComponent({ showEditButton });
expect(findEditButton().exists()).toBe(false);
});

View file

@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe GitlabSchema.types['ContainerRepositoryDetails'] do
fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete expiration_policy_cleanup_status tags project]
fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete expiration_policy_cleanup_status tags size project]
it { expect(described_class.graphql_name).to eq('ContainerRepositoryDetails') }

View file

@ -6,8 +6,11 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
using RSpec::Parameterized::TableSyntax
include_context 'container registry client'
include_context 'container registry client stubs'
let(:path) { 'namespace/path/to/repository' }
let(:import_token) { 'import_token' }
let(:options) { { token: token, import_token: import_token } }
describe '#supports_gitlab_api?' do
subject { client.supports_gitlab_api? }
@ -121,6 +124,40 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
end
end
describe '#repository_details' do
let(:path) { 'namespace/path/to/repository' }
let(:response) { { foo: :bar, this: :is_a_test } }
let(:with_size) { true }
subject { client.repository_details(path, with_size: with_size) }
context 'with size' do
before do
stub_repository_details(path, with_size: with_size, respond_with: response)
end
it { is_expected.to eq(response.stringify_keys.deep_transform_values(&:to_s)) }
end
context 'without_size' do
let(:with_size) { false }
before do
stub_repository_details(path, with_size: with_size, respond_with: response)
end
it { is_expected.to eq(response.stringify_keys.deep_transform_values(&:to_s)) }
end
context 'with non successful response' do
before do
stub_repository_details(path, with_size: with_size, status_code: 404)
end
it { is_expected.to eq({}) }
end
end
describe '.supports_gitlab_api?' do
subject { described_class.supports_gitlab_api? }
@ -181,7 +218,7 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
def stub_pre_import(path, status_code, pre:)
stub_request(:put, "#{registry_api_url}/gitlab/v1/import/#{path}/?pre=#{pre}")
.with(headers: { 'Accept' => described_class::JSON_TYPE })
.with(headers: { 'Accept' => described_class::JSON_TYPE, 'Authorization' => "bearer #{import_token}" })
.to_return(status: status_code, body: '')
end
@ -194,11 +231,19 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
def stub_import_status(path, status)
stub_request(:get, "#{registry_api_url}/gitlab/v1/import/#{path}/")
.with(headers: { 'Accept' => described_class::JSON_TYPE })
.with(headers: { 'Accept' => described_class::JSON_TYPE, 'Authorization' => "bearer #{import_token}" })
.to_return(
status: 200,
body: { status: status }.to_json,
headers: { content_type: 'application/json' }
)
end
def stub_repository_details(path, with_size: true, status_code: 200, respond_with: {})
url = "#{registry_api_url}/gitlab/v1/repositories/#{path}/"
url += "?size=self" if with_size
stub_request(:get, url)
.with(headers: { 'Accept' => described_class::JSON_TYPE, 'Authorization' => "bearer #{token}" })
.to_return(status: status_code, body: respond_with.to_json, headers: { 'Content-Type' => described_class::JSON_TYPE })
end
end

View file

@ -4,10 +4,15 @@ require 'spec_helper'
RSpec.describe ContainerRegistry::Registry do
let(:path) { nil }
let(:registry) { described_class.new('http://example.com', path: path) }
let(:registry_api_url) { 'http://example.com' }
let(:registry) { described_class.new(registry_api_url, path: path) }
subject { registry }
before do
stub_container_registry_config(enabled: true, api_url: registry_api_url, key: 'spec/fixtures/x509_certificate_pk.key')
end
it { is_expected.to respond_to(:client) }
it { is_expected.to respond_to(:uri) }
it { is_expected.to respond_to(:path) }

View file

@ -7,13 +7,6 @@ RSpec.describe Gitlab::Database::LoadBalancing::Configuration, :request_store do
let(:db_config) { ActiveRecord::DatabaseConfigurations::HashConfig.new('test', 'ci', configuration_hash) }
let(:model) { double(:model, connection_db_config: db_config) }
before do
# It's confusing to think about these specs with this enabled by default so
# we make it disabled by default and just write the specific spec for when
# it's enabled
stub_feature_flags(force_no_sharing_primary_model: false)
end
describe '.for_model' do
context 'when load balancing is not configured' do
it 'uses the default settings' do

View file

@ -9,7 +9,7 @@ RSpec.describe Gitlab::Integrations::StiType do
context 'SQL SELECT' do
let(:expected_sql) do
<<~SQL.strip
SELECT "integrations".* FROM "integrations" WHERE "integrations"."type" = 'AsanaService'
FROM "integrations" WHERE "integrations"."type" = 'AsanaService'
SQL
end
@ -18,7 +18,7 @@ RSpec.describe Gitlab::Integrations::StiType do
Integration.where(type: type).to_sql
end
expect(sql_statements).to all(eq(expected_sql))
expect(sql_statements).to all(end_with(expected_sql))
end
end

View file

@ -653,6 +653,58 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
describe '#size' do
let(:on_com) { true }
let(:created_at) { described_class::MIGRATION_PHASE_1_STARTED_AT + 3.months }
subject { repository.size }
before do
allow(::Gitlab).to receive(:com?).and_return(on_com)
allow(repository).to receive(:created_at).and_return(created_at)
end
context 'supports gitlab api on .com with a recent repository' do
before do
expect(repository.gitlab_api_client).to receive(:supports_gitlab_api?).and_return(true)
expect(repository.gitlab_api_client).to receive(:repository_details).with(repository.path, with_size: true).and_return(response)
end
context 'with a size_bytes field' do
let(:response) { { 'size_bytes' => 12345 } }
it { is_expected.to eq(12345) }
end
context 'without a size_bytes field' do
let(:response) { { 'foo' => 'bar' } }
it { is_expected.to eq(nil) }
end
end
context 'does not support gitlab api' do
before do
expect(repository.gitlab_api_client).to receive(:supports_gitlab_api?).and_return(false)
expect(repository.gitlab_api_client).not_to receive(:repository_details)
end
it { is_expected.to eq(nil) }
end
context 'not on .com' do
let(:on_com) { false }
it { is_expected.to eq(nil) }
end
context 'with an old repository' do
let(:created_at) { described_class::MIGRATION_PHASE_1_STARTED_AT - 3.months }
it { is_expected.to eq(nil) }
end
end
describe '#reset_expiration_policy_started_at!' do
subject { repository.reset_expiration_policy_started_at! }

View file

@ -268,7 +268,7 @@ RSpec.describe Integration do
describe '.build_from_integration' do
context 'when integration is invalid' do
let(:invalid_integration) do
build(:prometheus_integration, :template, active: true, properties: {})
build(:prometheus_integration, :instance, active: true, properties: {})
.tap { |integration| integration.save!(validate: false) }
end

View file

@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe API::ContainerRepositories do
include_context 'container registry client stubs'
let_it_be(:project) { create(:project, :private) }
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
@ -103,6 +105,68 @@ RSpec.describe API::ContainerRepositories do
expect(json_response['tags_count']).to eq(2)
end
end
context 'with size param' do
let(:url) { "/registry/repositories/#{repository.id}?size=true" }
let(:on_com) { true }
let(:created_at) { ::ContainerRepository::MIGRATION_PHASE_1_STARTED_AT + 3.months }
before do
allow(::Gitlab).to receive(:com?).and_return(on_com)
repository.update_column(:created_at, created_at)
end
it 'returns a repository and its size' do
stub_container_registry_gitlab_api_support(supported: true) do |client|
stub_container_registry_gitlab_api_repository_details(client, path: repository.path, size_bytes: 12345)
end
subject
expect(json_response['size']).to eq(12345)
end
context 'with a network error' do
it 'returns an error message' do
stub_container_registry_gitlab_api_network_error
subject
expect(response).to have_gitlab_http_status(:service_unavailable)
expect(json_response['message']).to include('We are having trouble connecting to the Container Registry')
end
end
context 'with not supporting the gitlab api' do
it 'returns nil' do
stub_container_registry_gitlab_api_support(supported: false)
subject
expect(json_response['size']).to eq(nil)
end
end
context 'not on .com' do
let(:on_com) { false }
it 'returns nil' do
subject
expect(json_response['size']).to eq(nil)
end
end
context 'with an older container repository' do
let(:created_at) { ::ContainerRepository::MIGRATION_PHASE_1_STARTED_AT - 3.months }
it 'returns nil' do
subject
expect(json_response['size']).to eq(nil)
end
end
end
end
context 'with invalid repository id' do

View file

@ -170,17 +170,6 @@ RSpec.describe API::GenericPackages do
end
end
context 'generic_packages feature flag is disabled' do
it 'responds with 404 Not Found' do
stub_feature_flags(generic_packages: false)
project.add_developer(user)
authorize_upload_file(workhorse_headers.merge(personal_access_token_header))
expect(response).to have_gitlab_http_status(:not_found)
end
end
def authorize_upload_file(request_headers, package_name: 'mypackage', file_name: 'myfile.tar.gz')
url = "/projects/#{project.id}/packages/generic/#{package_name}/0.0.1/#{file_name}/authorize"

View file

@ -3,17 +3,19 @@ require 'spec_helper'
RSpec.describe 'container repository details' do
include_context 'container registry tags'
include_context 'container registry client stubs'
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
let_it_be_with_reload(:project) { create(:project) }
let_it_be(:container_repository) { create(:container_repository, project: project) }
let_it_be_with_reload(:container_repository) { create(:container_repository, project: project) }
let(:query) do
graphql_query_for(
'containerRepository',
{ id: container_repository_global_id },
all_graphql_fields_for('ContainerRepositoryDetails', excluded: ['pipeline'])
all_graphql_fields_for('ContainerRepositoryDetails', excluded: %w[pipeline size])
)
end
@ -220,6 +222,80 @@ RSpec.describe 'container repository details' do
end
end
context 'size field' do
let(:size_response) { container_repository_details_response.dig('size') }
let(:on_com) { true }
let(:created_at) { ::ContainerRepository::MIGRATION_PHASE_1_STARTED_AT + 3.months }
let(:variables) do
{ id: container_repository_global_id }
end
let(:query) do
<<~GQL
query($id: ID!) {
containerRepository(id: $id) {
size
}
}
GQL
end
before do
allow(::Gitlab).to receive(:com?).and_return(on_com)
container_repository.update_column(:created_at, created_at)
end
it 'returns the size' do
stub_container_registry_gitlab_api_support(supported: true) do |client|
stub_container_registry_gitlab_api_repository_details(client, path: container_repository.path, size_bytes: 12345)
end
subject
expect(size_response).to eq(12345)
end
context 'with a network error' do
it 'returns an error' do
stub_container_registry_gitlab_api_network_error
subject
expect_graphql_errors_to_include("Can't connect to the Container Registry. If this error persists, please review the troubleshooting documentation.")
end
end
context 'with not supporting the gitlab api' do
it 'returns nil' do
stub_container_registry_gitlab_api_support(supported: false)
subject
expect(size_response).to eq(nil)
end
end
context 'not on .com' do
let(:on_com) { false }
it 'returns nil' do
subject
expect(size_response).to eq(nil)
end
end
context 'with an older container repository' do
let(:created_at) { ::ContainerRepository::MIGRATION_PHASE_1_STARTED_AT - 3.months }
it 'returns nil' do
subject
expect(size_response).to eq(nil)
end
end
end
context 'with tags with a manifest containing nil fields' do
let(:tags_response) { container_repository_details_response.dig('tags', 'nodes') }
let(:errors) { container_repository_details_response.dig('errors') }

View file

@ -31,7 +31,7 @@ RSpec.describe EnvironmentEntity do
end
it 'exposes core elements of environment' do
expect(subject).to include(:id, :global_id, :name, :state, :environment_path)
expect(subject).to include(:id, :global_id, :name, :state, :environment_path, :tier)
end
it 'exposes folder path' do

View file

@ -13,7 +13,6 @@ RSpec.describe BulkCreateIntegrationService do
let_it_be(:excluded_project) { create(:project, group: excluded_group) }
let(:instance_integration) { create(:jira_integration, :instance) }
let(:template_integration) { create(:jira_integration, :template) }
let(:excluded_attributes) { %w[id project_id group_id inherit_from_id instance template created_at updated_at] }
shared_examples 'creates integration from batch ids' do

View file

@ -252,6 +252,20 @@ RSpec.configure do |config|
::Ci::ApplicationRecord.set_open_transactions_baseline
end
config.around do |example|
if example.metadata.fetch(:stub_feature_flags, true)
# It doesn't make sense for this to default to enabled as we only plan to
# use this temporarily to override an environment variable but eventually
# we'll just use the environment variable value when we've completed the
# gradual rollout. This stub must happen in around block as there are other
# around blocks in tests that will run before this and get the wrong
# database connection.
stub_feature_flags(force_no_sharing_primary_model: false)
end
example.run
end
config.append_after do
ApplicationRecord.reset_open_transactions_baseline
::Ci::ApplicationRecord.reset_open_transactions_baseline

View file

@ -0,0 +1,20 @@
# frozen_string_literal: true
RSpec.shared_context 'container registry client stubs' do
def stub_container_registry_gitlab_api_support(supported: true)
allow_next_instance_of(ContainerRegistry::GitlabApiClient) do |client|
allow(client).to receive(:supports_gitlab_api?).and_return(supported)
yield client if block_given?
end
end
def stub_container_registry_gitlab_api_repository_details(client, path:, size_bytes:)
allow(client).to receive(:repository_details).with(path, with_size: true).and_return('size_bytes' => size_bytes)
end
def stub_container_registry_gitlab_api_network_error(client_method: :supports_gitlab_api?)
allow_next_instance_of(ContainerRegistry::GitlabApiClient) do |client|
allow(client).to receive(client_method).and_raise(::Faraday::Error, nil, nil)
end
end
end