Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
f931527bc5
commit
2dedd78ef5
|
@ -448,7 +448,9 @@ db:backup_and_restore:
|
|||
- date
|
||||
- bundle exec rake gitlab:backup:restore
|
||||
rules:
|
||||
- changes: ["lib/backup/**/*"]
|
||||
- changes:
|
||||
- "lib/backup/**/*"
|
||||
- "lib/tasks/gitlab/backup.rake"
|
||||
|
||||
rspec:deprecations:
|
||||
extends:
|
||||
|
|
|
@ -46,7 +46,7 @@ review-build-cng:
|
|||
variables:
|
||||
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
|
||||
DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
|
||||
GITLAB_HELM_CHART_REF: "v4.12.0"
|
||||
GITLAB_HELM_CHART_REF: "v5.1.0"
|
||||
environment:
|
||||
name: review/${CI_COMMIT_REF_SLUG}${FREQUENCY}
|
||||
url: https://gitlab-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -487,7 +487,7 @@ gem 'toml-rb', '~> 2.0'
|
|||
gem 'flipper', '~> 0.21.0'
|
||||
gem 'flipper-active_record', '~> 0.21.0'
|
||||
gem 'flipper-active_support_cache_store', '~> 0.21.0'
|
||||
gem 'unleash', '~> 0.1.5'
|
||||
gem 'unleash', '~> 3.2.2'
|
||||
gem 'gitlab-experiment', '~> 0.6.2'
|
||||
|
||||
# Structured logging
|
||||
|
|
|
@ -1317,7 +1317,7 @@ GEM
|
|||
unicode-display_width (1.7.0)
|
||||
unicode_utils (1.4.0)
|
||||
uniform_notifier (1.13.0)
|
||||
unleash (0.1.5)
|
||||
unleash (3.2.2)
|
||||
murmurhash3 (~> 0.1.6)
|
||||
unparser (0.6.0)
|
||||
diff-lcs (~> 1.3)
|
||||
|
@ -1643,7 +1643,7 @@ DEPENDENCIES
|
|||
truncato (~> 0.7.11)
|
||||
u2f (~> 0.2.1)
|
||||
unf (~> 0.1.4)
|
||||
unleash (~> 0.1.5)
|
||||
unleash (~> 3.2.2)
|
||||
valid_email (~> 0.1)
|
||||
validates_hostname (~> 1.0.11)
|
||||
version_sorter (~> 2.2.4)
|
||||
|
|
|
@ -25,6 +25,8 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
oldIid: null,
|
||||
isEditing: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -72,6 +74,15 @@ export default {
|
|||
return this.labelsFetchPath || projectLabelsFetchPath;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
activeBoardItem(_, oldVal) {
|
||||
if (this.isEditing) {
|
||||
this.oldIid = oldVal.iid;
|
||||
} else {
|
||||
this.oldIid = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['setActiveBoardItemLabels', 'setError']),
|
||||
async setLabels(payload) {
|
||||
|
@ -84,8 +95,14 @@ export default {
|
|||
.filter((label) => !payload.find((selected) => selected.id === label.id))
|
||||
.map((label) => label.id);
|
||||
|
||||
const input = { addLabelIds, removeLabelIds, projectPath: this.projectPathForActiveIssue };
|
||||
const input = {
|
||||
addLabelIds,
|
||||
removeLabelIds,
|
||||
projectPath: this.projectPathForActiveIssue,
|
||||
iid: this.oldIid,
|
||||
};
|
||||
await this.setActiveBoardItemLabels(input);
|
||||
this.oldIid = null;
|
||||
} catch (e) {
|
||||
this.setError({ error: e, message: __('An error occurred while updating labels.') });
|
||||
} finally {
|
||||
|
@ -115,6 +132,8 @@ export default {
|
|||
:title="__('Labels')"
|
||||
:loading="loading"
|
||||
data-testid="sidebar-labels"
|
||||
@open="isEditing = true"
|
||||
@close="isEditing = false"
|
||||
>
|
||||
<template #collapsed>
|
||||
<gl-label
|
||||
|
|
|
@ -575,7 +575,7 @@ export default {
|
|||
mutation: issueSetLabelsMutation,
|
||||
variables: {
|
||||
input: {
|
||||
iid: String(activeBoardItem.iid),
|
||||
iid: input.iid || String(activeBoardItem.iid),
|
||||
addLabelIds: input.addLabelIds ?? [],
|
||||
removeLabelIds: input.removeLabelIds ?? [],
|
||||
projectPath: input.projectPath,
|
||||
|
@ -588,7 +588,7 @@ export default {
|
|||
}
|
||||
|
||||
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
|
||||
itemId: activeBoardItem.id,
|
||||
itemId: getIdFromGraphQLId(data.updateIssue?.issue?.id) || activeBoardItem.id,
|
||||
prop: 'labels',
|
||||
value: data.updateIssue.issue.labels.nodes,
|
||||
});
|
||||
|
|
|
@ -175,7 +175,7 @@ export default {
|
|||
>
|
||||
<template #actions>
|
||||
<blob-edit
|
||||
v-if="!isBinary"
|
||||
:show-edit-button="!isBinary"
|
||||
:edit-path="blobInfo.editBlobPath"
|
||||
:web-ide-path="blobInfo.ideEditPath"
|
||||
/>
|
||||
|
|
|
@ -15,6 +15,10 @@ export default {
|
|||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
showEditButton: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
editPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -30,17 +34,31 @@ export default {
|
|||
<template>
|
||||
<web-ide-link
|
||||
v-if="glFeatures.consolidatedEditButton"
|
||||
:show-edit-button="showEditButton"
|
||||
class="gl-mr-3"
|
||||
:edit-url="editPath"
|
||||
:web-ide-url="webIdePath"
|
||||
:is-blob="true"
|
||||
/>
|
||||
<div v-else>
|
||||
<gl-button class="gl-mr-2" category="primary" variant="confirm" :href="editPath">
|
||||
<gl-button
|
||||
v-if="showEditButton"
|
||||
class="gl-mr-2"
|
||||
category="primary"
|
||||
variant="confirm"
|
||||
:href="editPath"
|
||||
data-testid="edit"
|
||||
>
|
||||
{{ $options.i18n.edit }}
|
||||
</gl-button>
|
||||
|
||||
<gl-button class="gl-mr-3" category="primary" variant="confirm" :href="webIdePath">
|
||||
<gl-button
|
||||
class="gl-mr-3"
|
||||
category="primary"
|
||||
variant="confirm"
|
||||
:href="webIdePath"
|
||||
data-testid="web-ide"
|
||||
>
|
||||
{{ $options.i18n.webIde }}
|
||||
</gl-button>
|
||||
</div>
|
||||
|
|
|
@ -8,6 +8,21 @@ module Ci
|
|||
belongs_to :processable, class_name: 'Ci::Processable', foreign_key: 'build_id', inverse_of: :resource
|
||||
|
||||
scope :free, -> { where(processable: nil) }
|
||||
scope :retained, -> { where.not(processable: nil) }
|
||||
scope :retained_by, -> (processable) { where(processable: processable) }
|
||||
|
||||
class << self
|
||||
# In some cases, state machine hooks in `Ci::Build` are skipped
|
||||
# even if the job status transitions to a complete state.
|
||||
# For example, `Ci::Build#doom!` (a.k.a `data_integrity_failure`) doesn't execute state machine hooks.
|
||||
# To handle these edge cases, we check the staleness of the jobs that currently
|
||||
# assigned to the resources, and release if it's stale.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/335537#note_632925914 for more information.
|
||||
def stale_processables
|
||||
Ci::Processable.where(id: retained.select(:build_id))
|
||||
.complete
|
||||
.updated_at_before(5.minutes.ago)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,6 +58,7 @@ class CommitStatus < ApplicationRecord
|
|||
scope :in_pipelines, ->(pipelines) { where(pipeline: pipelines) }
|
||||
scope :eager_load_pipeline, -> { eager_load(:pipeline, project: { namespace: :route }) }
|
||||
scope :with_pipeline, -> { joins(:pipeline) }
|
||||
scope :updated_at_before, ->(date) { where('updated_at < ?', date) }
|
||||
scope :updated_before, ->(lookback:, timeout:) {
|
||||
where('(ci_builds.created_at BETWEEN ? AND ?) AND (ci_builds.updated_at BETWEEN ? AND ?)', lookback, timeout, lookback, timeout)
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ module Ci
|
|||
scope :running_or_pending, -> { with_status(:running, :pending) }
|
||||
scope :finished, -> { with_status(:success, :failed, :canceled) }
|
||||
scope :failed_or_canceled, -> { with_status(:failed, :canceled) }
|
||||
scope :complete, -> { with_status(completed_statuses) }
|
||||
scope :incomplete, -> { without_statuses(completed_statuses) }
|
||||
|
||||
scope :cancelable, -> do
|
||||
|
|
|
@ -938,8 +938,8 @@ class Repository
|
|||
end
|
||||
end
|
||||
|
||||
def fetch_as_mirror(url, forced: false, refmap: :all_refs, remote_name: nil, prune: true)
|
||||
fetch_remote(remote_name, url: url, refmap: refmap, forced: forced, prune: prune)
|
||||
def fetch_as_mirror(url, forced: false, refmap: :all_refs, prune: true, http_authorization_header: "")
|
||||
fetch_remote(url, refmap: refmap, forced: forced, prune: prune, http_authorization_header: http_authorization_header)
|
||||
end
|
||||
|
||||
def fetch_source_branch!(source_repository, source_branch, local_ref)
|
||||
|
|
|
@ -5,6 +5,8 @@ module Ci
|
|||
class AssignResourceFromResourceGroupService < ::BaseService
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def execute(resource_group)
|
||||
release_resource_from_stale_jobs(resource_group)
|
||||
|
||||
free_resources = resource_group.resources.free.count
|
||||
|
||||
resource_group.processables.waiting_for_resource.take(free_resources).each do |processable|
|
||||
|
@ -12,6 +14,14 @@ module Ci
|
|||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
private
|
||||
|
||||
def release_resource_from_stale_jobs(resource_group)
|
||||
resource_group.resources.stale_processables.find_each do |processable|
|
||||
resource_group.release_resource_from(processable)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: changes_batch_commits
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66731
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/336992
|
||||
milestone: '14.2'
|
||||
type: development
|
||||
group: group::gitaly
|
||||
default_enabled: false
|
|
@ -40,9 +40,11 @@ The newly created epic opens.
|
|||
If you select **Inherited**:
|
||||
|
||||
- For the **start date**: GitLab scans all child epics and issues assigned to the epic,
|
||||
and sets the start date to match the earliest found start date or milestone.
|
||||
- For the **due date**: GitLab sets the due date to match the latest due date or
|
||||
milestone found among its child epics and issues.
|
||||
and sets the start date to match the earliest start date found in the child epics or the milestone
|
||||
assigned to the issues.
|
||||
- For the **due date**: GitLab scans all child epics and issues assigned to the epic,
|
||||
and sets the due date to match the latest due date found in the child epics or the milestone
|
||||
assigned to the issues.
|
||||
|
||||
These are dynamic dates and recalculated if any of the following occur:
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ fork from its upstream project. Go to **Settings > Advanced Settings** and
|
|||
|
||||
For more information, [see the forking workflow documentation](../repository/forking_workflow.md).
|
||||
|
||||
## By sending an email **(FREE SELF)**
|
||||
## By sending an email
|
||||
|
||||
> The format of the generated email address changed in GitLab 11.7.
|
||||
The earlier format is still supported so existing aliases
|
||||
|
|
|
@ -7,7 +7,6 @@ module Gitlab
|
|||
attr_reader :project, :project_key, :repository_slug, :client, :errors, :users, :already_imported_cache_key
|
||||
attr_accessor :logger
|
||||
|
||||
REMOTE_NAME = 'bitbucket_server'
|
||||
BATCH_SIZE = 100
|
||||
# The base cache key to use for tracking already imported objects.
|
||||
ALREADY_IMPORTED_CACHE_KEY =
|
||||
|
@ -142,7 +141,7 @@ module Gitlab
|
|||
log_info(stage: 'import_repository', message: 'starting import')
|
||||
|
||||
project.ensure_repository
|
||||
project.repository.fetch_as_mirror(project.import_url, refmap: self.class.refmap, remote_name: REMOTE_NAME)
|
||||
project.repository.fetch_as_mirror(project.import_url, refmap: self.class.refmap)
|
||||
|
||||
log_info(stage: 'import_repository', message: 'finished import')
|
||||
rescue Gitlab::Shell::Error => e
|
||||
|
|
|
@ -29,11 +29,48 @@ module Gitlab
|
|||
true
|
||||
end
|
||||
|
||||
# All commits which have been newly introduced via any of the given
|
||||
# changes. This set may also contain commits which are not referenced by
|
||||
# any of the new revisions.
|
||||
def commits
|
||||
newrevs = @changes.map do |change|
|
||||
newrev = change[:newrev]
|
||||
newrev unless newrev.blank? || Gitlab::Git.blank_ref?(newrev)
|
||||
end.compact
|
||||
|
||||
return [] if newrevs.empty?
|
||||
|
||||
@commits ||= project.repository.new_commits(newrevs)
|
||||
end
|
||||
|
||||
# All commits which have been newly introduced via the given revision.
|
||||
def commits_for(newrev)
|
||||
commits_by_id = commits.index_by(&:id)
|
||||
|
||||
result = []
|
||||
pending = [newrev]
|
||||
|
||||
# We go up the parent chain of our newrev and collect all commits which
|
||||
# are new. In case a commit's ID cannot be found in the set of new
|
||||
# commits, then it must already be a preexisting commit.
|
||||
pending.each do |rev|
|
||||
commit = commits_by_id[rev]
|
||||
next if commit.nil?
|
||||
|
||||
pending.push(*commit.parent_ids)
|
||||
result << commit
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def single_access_checks!
|
||||
# Iterate over all changes to find if user allowed all of them to be applied
|
||||
changes.each do |change|
|
||||
commits = Gitlab::Lazy.new { commits_for(change[:newrev]) } if Feature.enabled?(:changes_batch_commits)
|
||||
|
||||
# If user does not have access to make at least one change, cancel all
|
||||
# push by allowing the exception to bubble up
|
||||
Checks::SingleChangeAccess.new(
|
||||
|
@ -41,7 +78,8 @@ module Gitlab
|
|||
user_access: user_access,
|
||||
project: project,
|
||||
protocol: protocol,
|
||||
logger: logger
|
||||
logger: logger,
|
||||
commits: commits
|
||||
).validate!
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ module Gitlab
|
|||
|
||||
def initialize(
|
||||
change, user_access:, project:,
|
||||
protocol:, logger:
|
||||
protocol:, logger:, commits: nil
|
||||
)
|
||||
@oldrev, @newrev, @ref = change.values_at(:oldrev, :newrev, :ref)
|
||||
@branch_name = Gitlab::Git.branch_name(@ref)
|
||||
|
@ -19,6 +19,7 @@ module Gitlab
|
|||
@user_access = user_access
|
||||
@project = project
|
||||
@protocol = protocol
|
||||
@commits = commits
|
||||
|
||||
@logger = logger
|
||||
@logger.append_message("Running checks for ref: #{@branch_name || @tag_name}")
|
||||
|
|
|
@ -699,11 +699,11 @@ module Gitlab
|
|||
write_ref(ref, start_point)
|
||||
end
|
||||
|
||||
def find_remote_root_ref(remote_name, remote_url, authorization = nil)
|
||||
return unless remote_name.present? && remote_url.present?
|
||||
def find_remote_root_ref(remote_url, authorization = nil)
|
||||
return unless remote_url.present?
|
||||
|
||||
wrapped_gitaly_errors do
|
||||
gitaly_remote_client.find_remote_root_ref(remote_name, remote_url, authorization)
|
||||
gitaly_remote_client.find_remote_root_ref(remote_url, authorization)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -803,18 +803,18 @@ module Gitlab
|
|||
# no_tags - should we use --no-tags flag?
|
||||
# prune - should we use --prune flag?
|
||||
# check_tags_changed - should we ask gitaly to calculate whether any tags changed?
|
||||
def fetch_remote(remote, url: nil, refmap: nil, ssh_auth: nil, forced: false, no_tags: false, prune: true, check_tags_changed: false)
|
||||
def fetch_remote(url, refmap: nil, ssh_auth: nil, forced: false, no_tags: false, prune: true, check_tags_changed: false, http_authorization_header: "")
|
||||
wrapped_gitaly_errors do
|
||||
gitaly_repository_client.fetch_remote(
|
||||
remote,
|
||||
url: url,
|
||||
url,
|
||||
refmap: refmap,
|
||||
ssh_auth: ssh_auth,
|
||||
forced: forced,
|
||||
no_tags: no_tags,
|
||||
prune: prune,
|
||||
check_tags_changed: check_tags_changed,
|
||||
timeout: GITLAB_PROJECTS_TIMEOUT
|
||||
timeout: GITLAB_PROJECTS_TIMEOUT,
|
||||
http_authorization_header: http_authorization_header
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -924,12 +924,6 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def delete_config(*keys)
|
||||
wrapped_gitaly_errors do
|
||||
gitaly_repository_client.delete_config(keys)
|
||||
end
|
||||
end
|
||||
|
||||
def disconnect_alternates
|
||||
wrapped_gitaly_errors do
|
||||
gitaly_repository_client.disconnect_alternates
|
||||
|
|
|
@ -26,8 +26,7 @@ module Gitlab
|
|||
@storage = repository.storage
|
||||
end
|
||||
|
||||
# The remote_name parameter is deprecated and will be removed soon.
|
||||
def find_remote_root_ref(remote_name, remote_url, authorization)
|
||||
def find_remote_root_ref(remote_url, authorization)
|
||||
request = Gitaly::FindRemoteRootRefRequest.new(repository: @gitaly_repo,
|
||||
remote_url: remote_url,
|
||||
http_authorization_header: authorization)
|
||||
|
|
|
@ -73,18 +73,21 @@ module Gitlab
|
|||
# rubocop: disable Metrics/ParameterLists
|
||||
# The `remote` parameter is going away soonish anyway, at which point the
|
||||
# Rubocop warning can be enabled again.
|
||||
def fetch_remote(remote, url:, refmap:, ssh_auth:, forced:, no_tags:, timeout:, prune: true, check_tags_changed: false)
|
||||
def fetch_remote(url, refmap:, ssh_auth:, forced:, no_tags:, timeout:, prune: true, check_tags_changed: false, http_authorization_header: "")
|
||||
request = Gitaly::FetchRemoteRequest.new(
|
||||
repository: @gitaly_repo, remote: remote, force: forced,
|
||||
no_tags: no_tags, timeout: timeout, no_prune: !prune,
|
||||
check_tags_changed: check_tags_changed
|
||||
repository: @gitaly_repo,
|
||||
force: forced,
|
||||
no_tags: no_tags,
|
||||
timeout: timeout,
|
||||
no_prune: !prune,
|
||||
check_tags_changed: check_tags_changed,
|
||||
remote_params: Gitaly::Remote.new(
|
||||
url: url,
|
||||
mirror_refmaps: Array.wrap(refmap).map(&:to_s),
|
||||
http_authorization_header: http_authorization_header
|
||||
)
|
||||
)
|
||||
|
||||
if url
|
||||
request.remote_params = Gitaly::Remote.new(url: url,
|
||||
mirror_refmaps: Array.wrap(refmap).map(&:to_s))
|
||||
end
|
||||
|
||||
if ssh_auth&.ssh_mirror_url?
|
||||
if ssh_auth.ssh_key_auth? && ssh_auth.ssh_private_key.present?
|
||||
request.ssh_key = ssh_auth.ssh_private_key
|
||||
|
@ -297,22 +300,6 @@ module Gitlab
|
|||
nil
|
||||
end
|
||||
|
||||
def delete_config(keys)
|
||||
return if keys.empty?
|
||||
|
||||
request = Gitaly::DeleteConfigRequest.new(repository: @gitaly_repo, keys: keys)
|
||||
|
||||
GitalyClient.call(
|
||||
@storage,
|
||||
:repository_service,
|
||||
:delete_config,
|
||||
request,
|
||||
timeout: GitalyClient.fast_timeout
|
||||
)
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def license_short_name
|
||||
request = Gitaly::FindLicenseRequest.new(repository: @gitaly_repo)
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ module Gitlab
|
|||
# updating the timestamp.
|
||||
project.update_column(:last_repository_updated_at, Time.zone.now)
|
||||
|
||||
project.repository.fetch_remote('github', url: project.import_url, refmap: Gitlab::GithubImport.refmap, forced: false)
|
||||
project.repository.fetch_remote(project.import_url, refmap: Gitlab::GithubImport.refmap, forced: false)
|
||||
|
||||
pname = project.path_with_namespace
|
||||
|
||||
|
|
|
@ -33,41 +33,43 @@ RSpec.describe Ci::RunnersFinder do
|
|||
end
|
||||
end
|
||||
|
||||
context 'filter by search term' do
|
||||
it 'calls Ci::Runner.search' do
|
||||
expect(Ci::Runner).to receive(:search).with('term').and_call_original
|
||||
context 'filtering' do
|
||||
context 'by search term' do
|
||||
it 'calls Ci::Runner.search' do
|
||||
expect(Ci::Runner).to receive(:search).with('term').and_call_original
|
||||
|
||||
described_class.new(current_user: admin, params: { search: 'term' }).execute
|
||||
described_class.new(current_user: admin, params: { search: 'term' }).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'filter by status' do
|
||||
Ci::Runner::AVAILABLE_STATUSES.each do |status|
|
||||
it "calls the corresponding :#{status} scope on Ci::Runner" do
|
||||
expect(Ci::Runner).to receive(status.to_sym).and_call_original
|
||||
context 'by status' do
|
||||
Ci::Runner::AVAILABLE_STATUSES.each do |status|
|
||||
it "calls the corresponding :#{status} scope on Ci::Runner" do
|
||||
expect(Ci::Runner).to receive(status.to_sym).and_call_original
|
||||
|
||||
described_class.new(current_user: admin, params: { status_status: status }).execute
|
||||
described_class.new(current_user: admin, params: { status_status: status }).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'by runner type' do
|
||||
it 'calls the corresponding scope on Ci::Runner' do
|
||||
expect(Ci::Runner).to receive(:project_type).and_call_original
|
||||
|
||||
described_class.new(current_user: admin, params: { type_type: 'project_type' }).execute
|
||||
end
|
||||
end
|
||||
|
||||
context 'by tag_name' do
|
||||
it 'calls the corresponding scope on Ci::Runner' do
|
||||
expect(Ci::Runner).to receive(:tagged_with).with(%w[tag1 tag2]).and_call_original
|
||||
|
||||
described_class.new(current_user: admin, params: { tag_name: %w[tag1 tag2] }).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'filter by runner type' do
|
||||
it 'calls the corresponding scope on Ci::Runner' do
|
||||
expect(Ci::Runner).to receive(:project_type).and_call_original
|
||||
|
||||
described_class.new(current_user: admin, params: { type_type: 'project_type' }).execute
|
||||
end
|
||||
end
|
||||
|
||||
context 'filter by tag_name' do
|
||||
it 'calls the corresponding scope on Ci::Runner' do
|
||||
expect(Ci::Runner).to receive(:tagged_with).with(%w[tag1 tag2]).and_call_original
|
||||
|
||||
described_class.new(current_user: admin, params: { tag_name: %w[tag1 tag2] }).execute
|
||||
end
|
||||
end
|
||||
|
||||
context 'sort' do
|
||||
context 'sorting' do
|
||||
let_it_be(:runner1) { create :ci_runner, created_at: '2018-07-12 07:00', contacted_at: 1.minute.ago }
|
||||
let_it_be(:runner2) { create :ci_runner, created_at: '2018-07-12 08:00', contacted_at: 3.minutes.ago }
|
||||
let_it_be(:runner3) { create :ci_runner, created_at: '2018-07-12 09:00', contacted_at: 2.minutes.ago }
|
||||
|
@ -121,7 +123,7 @@ RSpec.describe Ci::RunnersFinder do
|
|||
end
|
||||
end
|
||||
|
||||
context 'non admin user' do
|
||||
context 'by non admin user' do
|
||||
it 'returns no runners' do
|
||||
user = create :user
|
||||
create :ci_runner, active: true
|
||||
|
@ -131,7 +133,7 @@ RSpec.describe Ci::RunnersFinder do
|
|||
end
|
||||
end
|
||||
|
||||
context 'user is nil' do
|
||||
context 'when user is nil' do
|
||||
it 'returns no runners' do
|
||||
user = nil
|
||||
create :ci_runner, active: true
|
||||
|
@ -182,85 +184,69 @@ RSpec.describe Ci::RunnersFinder do
|
|||
describe '#execute' do
|
||||
subject { described_class.new(current_user: user, group: group, params: params).execute }
|
||||
|
||||
context 'no params' do
|
||||
context 'with user as group owner' do
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
it 'returns all runners' do
|
||||
expect(subject).to eq([runner_project_7, runner_project_6, runner_project_5,
|
||||
runner_project_4, runner_project_3, runner_project_2,
|
||||
runner_project_1, runner_sub_group_4, runner_sub_group_3,
|
||||
runner_sub_group_2, runner_sub_group_1, runner_group])
|
||||
context 'passing no params' do
|
||||
it 'returns all descendant runners' do
|
||||
expect(subject).to eq([runner_project_7, runner_project_6, runner_project_5,
|
||||
runner_project_4, runner_project_3, runner_project_2,
|
||||
runner_project_1, runner_sub_group_4, runner_sub_group_3,
|
||||
runner_sub_group_2, runner_sub_group_1, runner_group])
|
||||
end
|
||||
end
|
||||
|
||||
context 'with sort param' do
|
||||
let(:params) { { sort: 'contacted_asc' } }
|
||||
|
||||
it 'sorts by specified attribute' do
|
||||
expect(subject).to eq([runner_group, runner_sub_group_1, runner_sub_group_2,
|
||||
runner_sub_group_3, runner_sub_group_4, runner_project_1,
|
||||
runner_project_2, runner_project_3, runner_project_4,
|
||||
runner_project_5, runner_project_6, runner_project_7])
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
context 'by search term' do
|
||||
let(:params) { { search: 'runner_project_search' } }
|
||||
|
||||
it 'returns correct runner' do
|
||||
expect(subject).to eq([runner_project_3])
|
||||
end
|
||||
end
|
||||
|
||||
context 'by status' do
|
||||
let(:params) { { status_status: 'paused' } }
|
||||
|
||||
it 'returns correct runner' do
|
||||
expect(subject).to eq([runner_sub_group_1])
|
||||
end
|
||||
end
|
||||
|
||||
context 'by tag_name' do
|
||||
let(:params) { { tag_name: %w[runner_tag] } }
|
||||
|
||||
it 'returns correct runner' do
|
||||
expect(subject).to eq([runner_project_5])
|
||||
end
|
||||
end
|
||||
|
||||
context 'by runner type' do
|
||||
let(:params) { { type_type: 'project_type' } }
|
||||
|
||||
it 'returns correct runners' do
|
||||
expect(subject).to eq([runner_project_7, runner_project_6,
|
||||
runner_project_5, runner_project_4,
|
||||
runner_project_3, runner_project_2, runner_project_1])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with sort param' do
|
||||
let(:params) { { sort: 'contacted_asc' } }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
it 'sorts by specified attribute' do
|
||||
expect(subject).to eq([runner_group, runner_sub_group_1, runner_sub_group_2,
|
||||
runner_sub_group_3, runner_sub_group_4, runner_project_1,
|
||||
runner_project_2, runner_project_3, runner_project_4,
|
||||
runner_project_5, runner_project_6, runner_project_7])
|
||||
end
|
||||
end
|
||||
|
||||
context 'filter by search term' do
|
||||
let(:params) { { search: 'runner_project_search' } }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
it 'returns correct runner' do
|
||||
expect(subject).to eq([runner_project_3])
|
||||
end
|
||||
end
|
||||
|
||||
context 'filter by status' do
|
||||
let(:params) { { status_status: 'paused' } }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
it 'returns correct runner' do
|
||||
expect(subject).to eq([runner_sub_group_1])
|
||||
end
|
||||
end
|
||||
|
||||
context 'filter by tag_name' do
|
||||
let(:params) { { tag_name: %w[runner_tag] } }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
it 'returns correct runner' do
|
||||
expect(subject).to eq([runner_project_5])
|
||||
end
|
||||
end
|
||||
|
||||
context 'filter by runner type' do
|
||||
let(:params) { { type_type: 'project_type' } }
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
it 'returns correct runners' do
|
||||
expect(subject).to eq([runner_project_7, runner_project_6,
|
||||
runner_project_5, runner_project_4,
|
||||
runner_project_3, runner_project_2, runner_project_1])
|
||||
end
|
||||
end
|
||||
|
||||
context 'user has no access to runners' do
|
||||
context 'when user is not group owner' do
|
||||
where(:user_permission) do
|
||||
[:maintainer, :developer, :reporter, :guest]
|
||||
end
|
||||
|
@ -276,13 +262,13 @@ RSpec.describe Ci::RunnersFinder do
|
|||
end
|
||||
end
|
||||
|
||||
context 'user with no access' do
|
||||
context 'when user has no access' do
|
||||
it 'returns no runners' do
|
||||
expect(subject).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'user is nil' do
|
||||
context 'when user is nil' do
|
||||
let_it_be(:user) { nil }
|
||||
|
||||
it 'returns no runners' do
|
||||
|
@ -294,7 +280,7 @@ RSpec.describe Ci::RunnersFinder do
|
|||
describe '#sort_key' do
|
||||
subject { described_class.new(current_user: user, group: group, params: params).sort_key }
|
||||
|
||||
context 'no params' do
|
||||
context 'without params' do
|
||||
it 'returns created_at_desc' do
|
||||
expect(subject).to eq('created_at_desc')
|
||||
end
|
||||
|
|
|
@ -97,6 +97,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
|
|||
addLabelIds: TEST_LABELS.map((label) => label.id),
|
||||
projectPath: TEST_ISSUE_FULLPATH,
|
||||
removeLabelIds: [],
|
||||
iid: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -121,6 +122,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
|
|||
addLabelIds: [5, 7],
|
||||
removeLabelIds: [6],
|
||||
projectPath: TEST_ISSUE_FULLPATH,
|
||||
iid: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -309,6 +309,7 @@ describe('Blob content viewer component', () => {
|
|||
expect(findBlobEdit().props()).toMatchObject({
|
||||
editPath: editBlobPath,
|
||||
webIdePath: ideEditPath,
|
||||
showEditButton: true,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -326,10 +327,11 @@ describe('Blob content viewer component', () => {
|
|||
expect(findBlobEdit().props()).toMatchObject({
|
||||
editPath: editBlobPath,
|
||||
webIdePath: ideEditPath,
|
||||
showEditButton: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('does not render BlobHeaderEdit button when viewing a binary file', async () => {
|
||||
it('renders BlobHeaderEdit button for binary files', async () => {
|
||||
fullFactory({
|
||||
mockData: { blobInfo: richMockData, isBinary: true },
|
||||
stubs: {
|
||||
|
@ -340,7 +342,11 @@ describe('Blob content viewer component', () => {
|
|||
|
||||
await nextTick();
|
||||
|
||||
expect(findBlobEdit().exists()).toBe(false);
|
||||
expect(findBlobEdit().props()).toMatchObject({
|
||||
editPath: editBlobPath,
|
||||
webIdePath: ideEditPath,
|
||||
showEditButton: false,
|
||||
});
|
||||
});
|
||||
|
||||
describe('BlobButtonGroup', () => {
|
||||
|
|
|
@ -6,6 +6,7 @@ import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
|
|||
const DEFAULT_PROPS = {
|
||||
editPath: 'some_file.js/edit',
|
||||
webIdePath: 'some_file.js/ide/edit',
|
||||
showEditButton: true,
|
||||
};
|
||||
|
||||
describe('BlobEdit component', () => {
|
||||
|
@ -31,8 +32,8 @@ describe('BlobEdit component', () => {
|
|||
});
|
||||
|
||||
const findButtons = () => wrapper.findAll(GlButton);
|
||||
const findEditButton = () => findButtons().at(0);
|
||||
const findWebIdeButton = () => findButtons().at(1);
|
||||
const findEditButton = () => wrapper.find('[data-testid="edit"]');
|
||||
const findWebIdeButton = () => wrapper.find('[data-testid="web-ide"]');
|
||||
const findWebIdeLink = () => wrapper.find(WebIdeLink);
|
||||
|
||||
it('renders component', () => {
|
||||
|
@ -77,6 +78,23 @@ describe('BlobEdit component', () => {
|
|||
editUrl,
|
||||
webIdeUrl,
|
||||
isBlob: true,
|
||||
showEditButton: true,
|
||||
});
|
||||
});
|
||||
|
||||
describe('Without Edit button', () => {
|
||||
const showEditButton = false;
|
||||
|
||||
it('renders WebIdeLink component without an edit button', () => {
|
||||
createComponent(true, { showEditButton });
|
||||
|
||||
expect(findWebIdeLink().props()).toMatchObject({ showEditButton });
|
||||
});
|
||||
|
||||
it('does not render an Edit button', () => {
|
||||
createComponent(false, { showEditButton });
|
||||
|
||||
expect(findEditButton().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -32,8 +32,7 @@ RSpec.describe Gitlab::BitbucketServerImport::Importer do
|
|||
expect(subject).to receive(:delete_temp_branches)
|
||||
expect(project.repository).to receive(:fetch_as_mirror)
|
||||
.with('http://bitbucket:test@my-bitbucket',
|
||||
refmap: [:heads, :tags, '+refs/pull-requests/*/to:refs/merge-requests/*/head'],
|
||||
remote_name: 'bitbucket_server')
|
||||
refmap: [:heads, :tags, '+refs/pull-requests/*/to:refs/merge-requests/*/head'])
|
||||
|
||||
subject.execute
|
||||
end
|
||||
|
|
|
@ -3,40 +3,169 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Checks::ChangesAccess do
|
||||
include_context 'changes access checks context'
|
||||
|
||||
subject { changes_access }
|
||||
|
||||
describe '#validate!' do
|
||||
include_context 'changes access checks context'
|
||||
|
||||
before do
|
||||
allow(project).to receive(:lfs_enabled?).and_return(true)
|
||||
end
|
||||
|
||||
subject { changes_access }
|
||||
|
||||
context 'without failed checks' do
|
||||
it "doesn't raise an error" do
|
||||
expect { subject.validate! }.not_to raise_error
|
||||
shared_examples '#validate!' do
|
||||
before do
|
||||
allow(project).to receive(:lfs_enabled?).and_return(true)
|
||||
end
|
||||
|
||||
it 'calls lfs checks' do
|
||||
expect_next_instance_of(Gitlab::Checks::LfsCheck) do |instance|
|
||||
expect(instance).to receive(:validate!)
|
||||
context 'without failed checks' do
|
||||
it "doesn't raise an error" do
|
||||
expect { subject.validate! }.not_to raise_error
|
||||
end
|
||||
|
||||
subject.validate!
|
||||
it 'calls lfs checks' do
|
||||
expect_next_instance_of(Gitlab::Checks::LfsCheck) do |instance|
|
||||
expect(instance).to receive(:validate!)
|
||||
end
|
||||
|
||||
subject.validate!
|
||||
end
|
||||
end
|
||||
|
||||
context 'when time limit was reached' do
|
||||
it 'raises a TimeoutError' do
|
||||
logger = Gitlab::Checks::TimedLogger.new(start_time: timeout.ago, timeout: timeout)
|
||||
access = described_class.new(changes,
|
||||
project: project,
|
||||
user_access: user_access,
|
||||
protocol: protocol,
|
||||
logger: logger)
|
||||
|
||||
expect { access.validate! }.to raise_error(Gitlab::Checks::TimedLogger::TimeoutError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when time limit was reached' do
|
||||
it 'raises a TimeoutError' do
|
||||
logger = Gitlab::Checks::TimedLogger.new(start_time: timeout.ago, timeout: timeout)
|
||||
access = described_class.new(changes,
|
||||
project: project,
|
||||
user_access: user_access,
|
||||
protocol: protocol,
|
||||
logger: logger)
|
||||
context 'with batched commits enabled' do
|
||||
before do
|
||||
stub_feature_flags(changes_batch_commits: true)
|
||||
end
|
||||
|
||||
expect { access.validate! }.to raise_error(Gitlab::Checks::TimedLogger::TimeoutError)
|
||||
it_behaves_like '#validate!'
|
||||
end
|
||||
|
||||
context 'with batched commits disabled' do
|
||||
before do
|
||||
stub_feature_flags(changes_batch_commits: false)
|
||||
end
|
||||
|
||||
it_behaves_like '#validate!'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#commits' do
|
||||
it 'calls #new_commits' do
|
||||
expect(project.repository).to receive(:new_commits).and_return([])
|
||||
|
||||
expect(subject.commits).to eq([])
|
||||
end
|
||||
|
||||
context 'when changes contain empty revisions' do
|
||||
let(:changes) { [{ newrev: newrev }, { newrev: '' }, { newrev: Gitlab::Git::BLANK_SHA }] }
|
||||
let(:expected_commit) { instance_double(Commit) }
|
||||
|
||||
it 'returns only commits with non empty revisions' do
|
||||
expect(project.repository).to receive(:new_commits).with([newrev]) { [expected_commit] }
|
||||
expect(subject.commits).to eq([expected_commit])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#commits_for' do
|
||||
let(:new_commits) { [] }
|
||||
let(:expected_commits) { [] }
|
||||
|
||||
shared_examples 'a listing of new commits' do
|
||||
it 'returns expected commits' do
|
||||
expect(subject).to receive(:commits).and_return(new_commits)
|
||||
|
||||
expect(subject.commits_for(newrev)).to eq(expected_commits)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with no commits' do
|
||||
it_behaves_like 'a listing of new commits'
|
||||
end
|
||||
|
||||
context 'with unrelated commits' do
|
||||
let(:new_commits) { [create_commit('1234', %w[1111 2222])] }
|
||||
|
||||
it_behaves_like 'a listing of new commits'
|
||||
end
|
||||
|
||||
context 'with single related commit' do
|
||||
let(:new_commits) { [create_commit(newrev, %w[1111 2222])] }
|
||||
let(:expected_commits) { new_commits }
|
||||
|
||||
it_behaves_like 'a listing of new commits'
|
||||
end
|
||||
|
||||
context 'with single related and unrelated commit' do
|
||||
let(:new_commits) do
|
||||
[
|
||||
create_commit(newrev, %w[1111 2222]),
|
||||
create_commit('abcd', %w[1111 2222])
|
||||
]
|
||||
end
|
||||
|
||||
let(:expected_commits) do
|
||||
[create_commit(newrev, %w[1111 2222])]
|
||||
end
|
||||
|
||||
it_behaves_like 'a listing of new commits'
|
||||
end
|
||||
|
||||
context 'with multiple related commits' do
|
||||
let(:new_commits) do
|
||||
[
|
||||
create_commit(newrev, %w[1111]),
|
||||
create_commit('1111', %w[2222]),
|
||||
create_commit('abcd', [])
|
||||
]
|
||||
end
|
||||
|
||||
let(:expected_commits) do
|
||||
[
|
||||
create_commit(newrev, %w[1111]),
|
||||
create_commit('1111', %w[2222])
|
||||
]
|
||||
end
|
||||
|
||||
it_behaves_like 'a listing of new commits'
|
||||
end
|
||||
|
||||
context 'with merge commits' do
|
||||
let(:new_commits) do
|
||||
[
|
||||
create_commit(newrev, %w[1111 2222 3333]),
|
||||
create_commit('1111', []),
|
||||
create_commit('3333', %w[4444]),
|
||||
create_commit('4444', [])
|
||||
]
|
||||
end
|
||||
|
||||
let(:expected_commits) do
|
||||
[
|
||||
create_commit(newrev, %w[1111 2222 3333]),
|
||||
create_commit('1111', []),
|
||||
create_commit('3333', %w[4444]),
|
||||
create_commit('4444', [])
|
||||
]
|
||||
end
|
||||
|
||||
it_behaves_like 'a listing of new commits'
|
||||
end
|
||||
end
|
||||
|
||||
def create_commit(id, parent_ids)
|
||||
Gitlab::Git::Commit.new(project.repository, {
|
||||
id: id,
|
||||
parent_ids: parent_ids
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,5 +58,52 @@ RSpec.describe Gitlab::Checks::SingleChangeAccess do
|
|||
expect { access.validate! }.to raise_error(Gitlab::Checks::TimedLogger::TimeoutError)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#commits' do
|
||||
let(:expected_commits) { [Gitlab::Git::Commit.new(project.repository, { id: "1234" })] }
|
||||
|
||||
let(:access) do
|
||||
described_class.new(changes,
|
||||
project: project,
|
||||
user_access: user_access,
|
||||
protocol: protocol,
|
||||
logger: logger,
|
||||
commits: provided_commits)
|
||||
end
|
||||
|
||||
shared_examples '#commits' do
|
||||
it 'returns expected commits' do
|
||||
expect(access.commits).to eq(expected_commits)
|
||||
end
|
||||
|
||||
it 'returns expected commits on repeated calls' do
|
||||
expect(access.commits).to eq(expected_commits)
|
||||
expect(access.commits).to eq(expected_commits)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with provided commits' do
|
||||
let(:provided_commits) { expected_commits }
|
||||
|
||||
before do
|
||||
expect(project.repository).not_to receive(:new_commits)
|
||||
end
|
||||
|
||||
it_behaves_like '#commits'
|
||||
end
|
||||
|
||||
context 'without provided commits' do
|
||||
let(:provided_commits) { nil }
|
||||
|
||||
before do
|
||||
expect(project.repository)
|
||||
.to receive(:new_commits)
|
||||
.once
|
||||
.and_return(expected_commits)
|
||||
end
|
||||
|
||||
it_behaves_like '#commits'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -491,6 +491,8 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
|
|||
end
|
||||
|
||||
describe '#fetch_remote' do
|
||||
let(:url) { 'http://example.clom' }
|
||||
|
||||
it 'delegates to the gitaly RepositoryService' do
|
||||
ssh_auth = double(:ssh_auth)
|
||||
expected_opts = {
|
||||
|
@ -500,17 +502,17 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
|
|||
timeout: described_class::GITLAB_PROJECTS_TIMEOUT,
|
||||
prune: false,
|
||||
check_tags_changed: false,
|
||||
url: nil,
|
||||
refmap: nil
|
||||
refmap: nil,
|
||||
http_authorization_header: ""
|
||||
}
|
||||
|
||||
expect(repository.gitaly_repository_client).to receive(:fetch_remote).with('remote-name', expected_opts)
|
||||
expect(repository.gitaly_repository_client).to receive(:fetch_remote).with(url, expected_opts)
|
||||
|
||||
repository.fetch_remote('remote-name', ssh_auth: ssh_auth, forced: true, no_tags: true, prune: false, check_tags_changed: false)
|
||||
repository.fetch_remote(url, ssh_auth: ssh_auth, forced: true, no_tags: true, prune: false, check_tags_changed: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RepositoryService, :fetch_remote do
|
||||
subject { repository.fetch_remote('remote-name') }
|
||||
subject { repository.fetch_remote(url) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -584,29 +586,29 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
|
|||
expect_any_instance_of(Gitlab::GitalyClient::RemoteService)
|
||||
.to receive(:find_remote_root_ref).and_call_original
|
||||
|
||||
expect(repository.find_remote_root_ref('origin', SeedHelper::GITLAB_GIT_TEST_REPO_URL)).to eq 'master'
|
||||
expect(repository.find_remote_root_ref(SeedHelper::GITLAB_GIT_TEST_REPO_URL)).to eq 'master'
|
||||
end
|
||||
|
||||
it 'returns UTF-8' do
|
||||
expect(repository.find_remote_root_ref('origin', SeedHelper::GITLAB_GIT_TEST_REPO_URL)).to be_utf8
|
||||
expect(repository.find_remote_root_ref(SeedHelper::GITLAB_GIT_TEST_REPO_URL)).to be_utf8
|
||||
end
|
||||
|
||||
it 'returns nil when remote name is nil' do
|
||||
expect_any_instance_of(Gitlab::GitalyClient::RemoteService)
|
||||
.not_to receive(:find_remote_root_ref)
|
||||
|
||||
expect(repository.find_remote_root_ref(nil, nil)).to be_nil
|
||||
expect(repository.find_remote_root_ref(nil)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil when remote name is empty' do
|
||||
expect_any_instance_of(Gitlab::GitalyClient::RemoteService)
|
||||
.not_to receive(:find_remote_root_ref)
|
||||
|
||||
expect(repository.find_remote_root_ref('', '')).to be_nil
|
||||
expect(repository.find_remote_root_ref('')).to be_nil
|
||||
end
|
||||
|
||||
it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RemoteService, :find_remote_root_ref do
|
||||
subject { repository.find_remote_root_ref('origin', SeedHelper::GITLAB_GIT_TEST_REPO_URL) }
|
||||
subject { repository.find_remote_root_ref(SeedHelper::GITLAB_GIT_TEST_REPO_URL) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1810,34 +1812,6 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#delete_config' do
|
||||
let(:repository) { mutable_repository }
|
||||
let(:entries) do
|
||||
{
|
||||
'test.foo1' => 'bla bla',
|
||||
'test.foo2' => 1234,
|
||||
'test.foo3' => true
|
||||
}
|
||||
end
|
||||
|
||||
it 'can delete config settings' do
|
||||
entries.each do |key, value|
|
||||
repository_rugged.config[key] = value
|
||||
end
|
||||
|
||||
expect(repository.delete_config(*%w[does.not.exist test.foo1 test.foo2])).to be_nil
|
||||
|
||||
# Workaround for https://github.com/libgit2/rugged/issues/785: If
|
||||
# Gitaly changes .gitconfig while Rugged has the file loaded
|
||||
# Rugged::Repository#each_key will report stale values unless a
|
||||
# lookup is done first.
|
||||
expect(repository_rugged.config['test.foo1']).to be_nil
|
||||
config_keys = repository_rugged.config.each_key.to_a
|
||||
expect(config_keys).not_to include('test.foo1')
|
||||
expect(config_keys).not_to include('test.foo2')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#merge_to_ref' do
|
||||
let(:repository) { mutable_repository }
|
||||
let(:branch_head) { '6d394385cf567f80a8fd85055db1ab4c5295806f' }
|
||||
|
|
|
@ -6,11 +6,9 @@ RSpec.describe Gitlab::GitalyClient::RemoteService do
|
|||
let(:project) { create(:project) }
|
||||
let(:storage_name) { project.repository_storage }
|
||||
let(:relative_path) { project.disk_path + '.git' }
|
||||
let(:remote_name) { 'my-remote' }
|
||||
let(:client) { described_class.new(project.repository) }
|
||||
|
||||
describe '#find_remote_root_ref' do
|
||||
let(:remote) { 'origin' }
|
||||
let(:url) { 'http://git.example.com/my-repo.git' }
|
||||
let(:auth) { 'Basic secret' }
|
||||
let(:expected_params) { { remote_url: url, http_authorization_header: auth } }
|
||||
|
@ -22,7 +20,7 @@ RSpec.describe Gitlab::GitalyClient::RemoteService do
|
|||
.with(gitaly_request_with_params(expected_params), kind_of(Hash))
|
||||
.and_return(double(ref: 'master'))
|
||||
|
||||
expect(client.find_remote_root_ref(remote, url, auth)).to eq 'master'
|
||||
expect(client.find_remote_root_ref(url, auth)).to eq 'master'
|
||||
end
|
||||
|
||||
it 'ensure ref is a valid UTF-8 string' do
|
||||
|
@ -32,7 +30,7 @@ RSpec.describe Gitlab::GitalyClient::RemoteService do
|
|||
.with(gitaly_request_with_params(expected_params), kind_of(Hash))
|
||||
.and_return(double(ref: "an_invalid_ref_\xE5"))
|
||||
|
||||
expect(client.find_remote_root_ref(remote, url, auth)).to eq "an_invalid_ref_å"
|
||||
expect(client.find_remote_root_ref(url, auth)).to eq "an_invalid_ref_å"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -122,89 +122,75 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
|
|||
end
|
||||
|
||||
describe '#fetch_remote' do
|
||||
shared_examples 'a fetch' do
|
||||
it 'sends a fetch_remote_request message' do
|
||||
expected_remote_params = Gitaly::Remote.new(
|
||||
url: url, http_authorization_header: "", mirror_refmaps: [])
|
||||
let(:url) { 'https://example.com/git/repo.git' }
|
||||
|
||||
expected_request = gitaly_request_with_params(
|
||||
remote: remote,
|
||||
remote_params: url ? expected_remote_params : nil,
|
||||
ssh_key: '',
|
||||
known_hosts: '',
|
||||
force: false,
|
||||
no_tags: false,
|
||||
no_prune: false,
|
||||
check_tags_changed: false
|
||||
)
|
||||
it 'sends a fetch_remote_request message' do
|
||||
expected_request = gitaly_request_with_params(
|
||||
remote_params: Gitaly::Remote.new(
|
||||
url: url,
|
||||
http_authorization_header: "",
|
||||
mirror_refmaps: []
|
||||
),
|
||||
ssh_key: '',
|
||||
known_hosts: '',
|
||||
force: false,
|
||||
no_tags: false,
|
||||
no_prune: false,
|
||||
check_tags_changed: false
|
||||
)
|
||||
|
||||
expect_any_instance_of(Gitaly::RepositoryService::Stub)
|
||||
.to receive(:fetch_remote)
|
||||
.with(expected_request, kind_of(Hash))
|
||||
.and_return(double(value: true))
|
||||
expect_any_instance_of(Gitaly::RepositoryService::Stub)
|
||||
.to receive(:fetch_remote)
|
||||
.with(expected_request, kind_of(Hash))
|
||||
.and_return(double(value: true))
|
||||
|
||||
client.fetch_remote(remote, url: url, refmap: nil, ssh_auth: nil, forced: false, no_tags: false, timeout: 1, check_tags_changed: false)
|
||||
end
|
||||
|
||||
context 'SSH auth' do
|
||||
where(:ssh_mirror_url, :ssh_key_auth, :ssh_private_key, :ssh_known_hosts, :expected_params) do
|
||||
false | false | 'key' | 'known_hosts' | {}
|
||||
false | true | 'key' | 'known_hosts' | {}
|
||||
true | false | 'key' | 'known_hosts' | { known_hosts: 'known_hosts' }
|
||||
true | true | 'key' | 'known_hosts' | { ssh_key: 'key', known_hosts: 'known_hosts' }
|
||||
true | true | 'key' | nil | { ssh_key: 'key' }
|
||||
true | true | nil | 'known_hosts' | { known_hosts: 'known_hosts' }
|
||||
true | true | nil | nil | {}
|
||||
true | true | '' | '' | {}
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:ssh_auth) do
|
||||
double(
|
||||
:ssh_auth,
|
||||
ssh_mirror_url?: ssh_mirror_url,
|
||||
ssh_key_auth?: ssh_key_auth,
|
||||
ssh_private_key: ssh_private_key,
|
||||
ssh_known_hosts: ssh_known_hosts
|
||||
)
|
||||
end
|
||||
|
||||
it do
|
||||
expected_remote_params = Gitaly::Remote.new(
|
||||
url: url, http_authorization_header: "", mirror_refmaps: [])
|
||||
|
||||
expected_request = gitaly_request_with_params({
|
||||
remote: remote,
|
||||
remote_params: url ? expected_remote_params : nil,
|
||||
ssh_key: '',
|
||||
known_hosts: '',
|
||||
force: false,
|
||||
no_tags: false,
|
||||
no_prune: false
|
||||
}.update(expected_params))
|
||||
|
||||
expect_any_instance_of(Gitaly::RepositoryService::Stub)
|
||||
.to receive(:fetch_remote)
|
||||
.with(expected_request, kind_of(Hash))
|
||||
.and_return(double(value: true))
|
||||
|
||||
client.fetch_remote(remote, url: url, refmap: nil, ssh_auth: ssh_auth, forced: false, no_tags: false, timeout: 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
client.fetch_remote(url, refmap: nil, ssh_auth: nil, forced: false, no_tags: false, timeout: 1, check_tags_changed: false)
|
||||
end
|
||||
|
||||
context 'with remote' do
|
||||
it_behaves_like 'a fetch' do
|
||||
let(:remote) { 'remote-name' }
|
||||
let(:url) { nil }
|
||||
context 'SSH auth' do
|
||||
where(:ssh_mirror_url, :ssh_key_auth, :ssh_private_key, :ssh_known_hosts, :expected_params) do
|
||||
false | false | 'key' | 'known_hosts' | {}
|
||||
false | true | 'key' | 'known_hosts' | {}
|
||||
true | false | 'key' | 'known_hosts' | { known_hosts: 'known_hosts' }
|
||||
true | true | 'key' | 'known_hosts' | { ssh_key: 'key', known_hosts: 'known_hosts' }
|
||||
true | true | 'key' | nil | { ssh_key: 'key' }
|
||||
true | true | nil | 'known_hosts' | { known_hosts: 'known_hosts' }
|
||||
true | true | nil | nil | {}
|
||||
true | true | '' | '' | {}
|
||||
end
|
||||
end
|
||||
|
||||
context 'with URL' do
|
||||
it_behaves_like 'a fetch' do
|
||||
let(:remote) { "" }
|
||||
let(:url) { 'https://example.com/git/repo.git' }
|
||||
with_them do
|
||||
let(:ssh_auth) do
|
||||
double(
|
||||
:ssh_auth,
|
||||
ssh_mirror_url?: ssh_mirror_url,
|
||||
ssh_key_auth?: ssh_key_auth,
|
||||
ssh_private_key: ssh_private_key,
|
||||
ssh_known_hosts: ssh_known_hosts
|
||||
)
|
||||
end
|
||||
|
||||
it do
|
||||
expected_request = gitaly_request_with_params({
|
||||
remote_params: Gitaly::Remote.new(
|
||||
url: url,
|
||||
http_authorization_header: "",
|
||||
mirror_refmaps: []
|
||||
),
|
||||
ssh_key: '',
|
||||
known_hosts: '',
|
||||
force: false,
|
||||
no_tags: false,
|
||||
no_prune: false
|
||||
}.update(expected_params))
|
||||
|
||||
expect_any_instance_of(Gitaly::RepositoryService::Stub)
|
||||
.to receive(:fetch_remote)
|
||||
.with(expected_request, kind_of(Hash))
|
||||
.and_return(double(value: true))
|
||||
|
||||
client.fetch_remote(url, refmap: nil, ssh_auth: ssh_auth, forced: false, no_tags: false, timeout: 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -164,7 +164,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsImporter do
|
|||
|
||||
expect(project.repository)
|
||||
.to receive(:fetch_remote)
|
||||
.with('github', forced: false, url: url, refmap: Gitlab::GithubImport.refmap)
|
||||
.with(url, forced: false, refmap: Gitlab::GithubImport.refmap)
|
||||
|
||||
freeze_time do
|
||||
importer.update_repository
|
||||
|
|
|
@ -15,6 +15,22 @@ RSpec.describe Ci::Resource do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.retained' do
|
||||
subject { described_class.retained }
|
||||
|
||||
it "returns the resource if it's retained" do
|
||||
resource = create(:ci_resource, processable: create(:ci_build))
|
||||
|
||||
is_expected.to eq([resource])
|
||||
end
|
||||
|
||||
it "returns empty if it's not retained" do
|
||||
create(:ci_resource, processable: nil)
|
||||
|
||||
is_expected.to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe '.retained_by' do
|
||||
subject { described_class.retained_by(build) }
|
||||
|
||||
|
@ -25,4 +41,40 @@ RSpec.describe Ci::Resource do
|
|||
is_expected.to eq([resource])
|
||||
end
|
||||
end
|
||||
|
||||
describe '.stale_processables' do
|
||||
subject { resource_group.resources.stale_processables }
|
||||
|
||||
let!(:resource_group) { create(:ci_resource_group) }
|
||||
let!(:resource) { create(:ci_resource, processable: build, resource_group: resource_group) }
|
||||
|
||||
context 'when the processable is running' do
|
||||
let!(:build) { create(:ci_build, :running, resource_group: resource_group) }
|
||||
|
||||
before do
|
||||
# Creating unrelated builds to make sure the `retained` scope is working
|
||||
create(:ci_build, :running, resource_group: resource_group)
|
||||
end
|
||||
|
||||
it 'returns empty' do
|
||||
is_expected.to be_empty
|
||||
end
|
||||
|
||||
context 'and doomed' do
|
||||
before do
|
||||
build.doom!
|
||||
end
|
||||
|
||||
it 'returns empty' do
|
||||
is_expected.to be_empty
|
||||
end
|
||||
|
||||
it 'returns the stale prosessable a few minutes later' do
|
||||
travel_to(10.minutes.since) do
|
||||
is_expected.to eq([build])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -79,6 +79,15 @@ RSpec.describe CommitStatus do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.updated_at_before' do
|
||||
it 'finds the relevant records' do
|
||||
status = create(:commit_status, updated_at: 1.day.ago, project: project)
|
||||
create(:commit_status, updated_at: 1.day.since, project: project)
|
||||
|
||||
expect(described_class.updated_at_before(Time.current)).to eq([status])
|
||||
end
|
||||
end
|
||||
|
||||
describe '.updated_before' do
|
||||
let!(:lookback) { 5.days.ago }
|
||||
let!(:timeout) { 1.day.ago }
|
||||
|
|
|
@ -351,6 +351,18 @@ RSpec.describe Ci::HasStatus do
|
|||
it_behaves_like 'not containing the job', status
|
||||
end
|
||||
end
|
||||
|
||||
describe '.complete' do
|
||||
subject { CommitStatus.complete }
|
||||
|
||||
described_class::COMPLETED_STATUSES.each do |status|
|
||||
it_behaves_like 'containing the job', status
|
||||
end
|
||||
|
||||
described_class::ACTIVE_STATUSES.each do |status|
|
||||
it_behaves_like 'not containing the job', status
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '::DEFAULT_STATUS' do
|
||||
|
|
|
@ -1096,15 +1096,14 @@ RSpec.describe Repository do
|
|||
|
||||
describe '#fetch_as_mirror' do
|
||||
let(:url) { "http://example.com" }
|
||||
let(:remote_name) { "remote-name" }
|
||||
|
||||
it 'fetches the URL without creating a remote' do
|
||||
expect(repository)
|
||||
.to receive(:fetch_remote)
|
||||
.with(remote_name, url: url, forced: false, prune: true, refmap: :all_refs)
|
||||
.with(url, forced: false, prune: true, refmap: :all_refs, http_authorization_header: "")
|
||||
.and_return(nil)
|
||||
|
||||
repository.fetch_as_mirror(url, remote_name: remote_name)
|
||||
repository.fetch_as_mirror(url)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -51,14 +51,32 @@ RSpec.describe Ci::ResourceGroups::AssignResourceFromResourceGroupService do
|
|||
end
|
||||
|
||||
context 'when there are no available resources' do
|
||||
let!(:other_build) { create(:ci_build) }
|
||||
|
||||
before do
|
||||
resource_group.assign_resource_to(create(:ci_build))
|
||||
resource_group.assign_resource_to(other_build)
|
||||
end
|
||||
|
||||
it 'does not request resource' do
|
||||
expect_any_instance_of(Ci::Build).not_to receive(:enqueue_waiting_for_resource)
|
||||
|
||||
subject
|
||||
|
||||
expect(build.reload).to be_waiting_for_resource
|
||||
end
|
||||
|
||||
context 'when there is a stale build assigned to a resource' do
|
||||
before do
|
||||
other_build.doom!
|
||||
other_build.update_column(:updated_at, 10.minutes.ago)
|
||||
end
|
||||
|
||||
it 'releases the resource from the stale build and assignes to the waiting build' do
|
||||
subject
|
||||
|
||||
expect(build.reload).to be_pending
|
||||
expect(build.resource).to be_present
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue