Commit 483cfb7a authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-02-06

# Conflicts:
#	app/models/ci/job_artifact.rb
#	app/views/layouts/nav/sidebar/_group.html.haml
#	app/views/projects/clusters/index.html.haml
#	app/workers/build_finished_worker.rb
#	lib/api/users.rb
#	locale/gitlab.pot
#	spec/javascripts/clusters/clusters_bundle_spec.js
#	spec/models/ci/job_artifact_spec.rb
#	spec/models/project_services/kubernetes_service_spec.rb
#	spec/requests/api/jobs_spec.rb
#	spec/uploaders/job_artifact_uploader_spec.rb

[ci skip]
parents 79f6765f 7095c2bf
......@@ -427,6 +427,8 @@ end
# Gitaly GRPC client
gem 'gitaly-proto', '~> 0.83.0', require: 'gitaly'
# Locked until https://github.com/google/protobuf/issues/4210 is closed
gem 'google-protobuf', '= 3.5.1'
gem 'toml-rb', '~> 0.3.15', require: false
......
......@@ -365,7 +365,7 @@ GEM
mime-types (~> 3.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
google-protobuf (3.5.1.1)
google-protobuf (3.5.1)
googleapis-common-protos-types (1.0.1)
google-protobuf (~> 3.0)
googleauth (0.5.3)
......@@ -1102,6 +1102,7 @@ DEPENDENCIES
gollum-rugged_adapter (~> 0.4.4)
gon (~> 6.1.0)
google-api-client (~> 0.13.6)
google-protobuf (= 3.5.1)
gpgme
grape (~> 1.0)
grape-entity (~> 0.6.0)
......
......@@ -35,10 +35,11 @@ export default class Clusters {
clusterStatus,
clusterStatusReason,
helpPath,
ingressHelpPath,
} = document.querySelector('.js-edit-cluster-form').dataset;
this.store = new ClustersStore();
this.store.setHelpPath(helpPath);
this.store.setHelpPaths(helpPath, ingressHelpPath);
this.store.updateStatus(clusterStatus);
this.store.updateStatusReason(clusterStatusReason);
this.service = new ClustersService({
......@@ -93,6 +94,7 @@ export default class Clusters {
props: {
applications: this.state.applications,
helpPath: this.state.helpPath,
ingressHelpPath: this.state.ingressHelpPath,
},
});
},
......
......@@ -18,6 +18,11 @@
required: false,
default: '',
},
ingressHelpPath: {
type: String,
required: false,
default: '',
},
},
computed: {
generalApplicationDescription() {
......@@ -59,13 +64,28 @@
false,
);
const externalIpParagraph = sprintf(
_.escape(s__(
`ClusterIntegration|After installing Ingress, you will need to point your wildcard DNS
at the generated external IP address in order to view your app after it is deployed. %{ingressHelpLink}`,
)), {
ingressHelpLink: `<a href="${this.ingressHelpPath}">
${_.escape(s__('ClusterIntegration|More information'))}
</a>`,
},
false,
);
return `
<p>
${descriptionParagraph}
</p>
<p class="append-bottom-0">
<p>
${extraCostParagraph}
</p>
<p class="settings-message append-bottom-0">
${externalIpParagraph}
</p>
`;
},
gitlabRunnerDescription() {
......
......@@ -4,6 +4,7 @@ export default class ClusterStore {
constructor() {
this.state = {
helpPath: null,
ingressHelpPath: null,
status: null,
statusReason: null,
applications: {
......@@ -39,8 +40,9 @@ export default class ClusterStore {
};
}
setHelpPath(helpPath) {
setHelpPaths(helpPath, ingressHelpPath) {
this.state.helpPath = helpPath;
this.state.ingressHelpPath = ingressHelpPath;
}
updateStatus(status) {
......
......@@ -4,6 +4,11 @@
.page-title {
margin-top: 0;
.color-label {
font-size: $gl-font-size;
padding: $gl-vert-padding $label-padding-modal;
}
}
}
......
......@@ -565,6 +565,7 @@ $jq-ui-default-color: #777;
* Label
*/
$label-padding: 7px;
$label-padding-modal: 10px;
$label-gray-bg: #f8fafc;
$label-inverse-bg: #333;
$label-remove-border: rgba(0, 0, 0, .1);
......
......@@ -58,13 +58,13 @@
@media (min-width: $screen-sm-min) {
width: 200px;
margin-left: $gl-padding * 2;
margin-bottom: 0;
}
.label {
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
max-width: 100%;
}
}
......@@ -79,26 +79,33 @@
width: 100px;
margin-left: 10px;
margin-bottom: 0;
vertical-align: middle;
vertical-align: top;
}
}
.label-description {
display: block;
margin-bottom: 10px;
margin-left: 50px;
.description-text {
margin-bottom: $gl-padding;
}
a {
color: $blue-600;
}
@media (min-width: $screen-sm-min) {
display: inline-block;
width: 30%;
max-width: 50%;
margin-left: 10px;
margin-bottom: 0;
vertical-align: middle;
vertical-align: top;
}
}
.label {
padding: 8px 9px 9px;
padding: 8px 12px;
font-size: 14px;
}
}
......@@ -116,6 +123,12 @@
}
.manage-labels-list {
@media(min-width: $screen-md-min) {
&.content-list li {
padding: $gl-padding 0;
}
}
> li:not(.empty-message):not(.is-not-draggable) {
background-color: $white-light;
cursor: move;
......@@ -133,8 +146,6 @@
}
.btn-action {
color: $gl-text-color;
.fa {
font-size: 18px;
vertical-align: middle;
......@@ -155,10 +166,18 @@
float: right;
}
}
@media (max-width: $screen-xs-max) {
.dropdown-menu {
min-width: 100%;
}
}
}
.draggable-handler {
display: inline-block;
vertical-align: top;
margin: 5px 0;
opacity: 0;
transition: opacity .3s;
color: $gray-darkest;
......@@ -188,7 +207,7 @@
.toggle-priority {
display: inline-block;
vertical-align: middle;
vertical-align: top;
button {
border-color: transparent;
......@@ -255,6 +274,11 @@
}
.label-subscribe-button {
@media(min-width: $screen-md-min) {
min-width: 105px;
margin-left: $gl-padding;
}
.label-subscribe-button-icon {
&[disabled] {
opacity: 0.5;
......
......@@ -68,7 +68,7 @@ class Groups::LabelsController < Groups::ApplicationController
respond_to do |format|
format.html do
redirect_to group_labels_path(@group), status: 302, notice: 'Label was removed'
redirect_to group_labels_path(@group), status: 302, notice: "#{@label.name} deleted permanently"
end
format.js
end
......
......@@ -76,9 +76,9 @@ class Projects::WikisController < Projects::ApplicationController
@page = @project_wiki.find_page(params[:id])
if @page
@page_versions = Kaminari.paginate_array(@page.versions(page: params[:page]),
@page_versions = Kaminari.paginate_array(@page.versions(page: params[:page].to_i),
total_count: @page.count_versions)
.page(params[:page])
.page(params[:page])
else
redirect_to(
project_wiki_path(@project, :home),
......
module GroupsHelper
def group_nav_link_paths
%w[groups#projects groups#edit ci_cd#show ldap_group_links#index hooks#index audit_events#index pipeline_quota#index]
end
def can_change_group_visibility_level?(group)
can?(current_user, :change_visibility_level, group)
end
......
......@@ -11,12 +11,15 @@ module Ci
mount_uploader :file, JobArtifactUploader
<<<<<<< HEAD
after_save if: :file_changed?, on: [:create, :update] do
run_after_commit do
file.schedule_migration_to_object_storage
end
end
=======
>>>>>>> upstream/master
delegate :open, :exists?, to: :file
enum file_type: {
......
......@@ -520,10 +520,13 @@ class Project < ActiveRecord::Base
@repository ||= Repository.new(full_path, self, disk_path: disk_path)
end
def reload_repository!
def cleanup
@repository&.cleanup
@repository = nil
end
alias_method :reload_repository!, :cleanup
def container_registry_url
if Gitlab.config.registry.enabled
"#{Gitlab.config.registry.host_port}/#{full_path.downcase}"
......
......@@ -100,6 +100,10 @@ class Repository
alias_method :raw, :raw_repository
def cleanup
@raw_repository&.cleanup
end
# Return absolute path to repository
def path_to_repo
@path_to_repo ||= File.expand_path(
......
module Files
class CreateService < Files::BaseService
def create_commit!
handler = Lfs::FileModificationHandler.new(project, @branch_name)
handler.new_file(@file_path, @file_content) do |content_or_lfs_pointer|
create_transformed_commit(content_or_lfs_pointer)
end
end
private
def create_transformed_commit(content_or_lfs_pointer)
repository.create_file(
current_user,
@file_path,
@file_content,
content_or_lfs_pointer,
message: @commit_message,
branch_name: @branch_name,
author_email: @author_email,
......
module Lfs
class FileModificationHandler
attr_reader :project, :branch_name
delegate :repository, to: :project
def initialize(project, branch_name)
@project = project
@branch_name = branch_name
end
def new_file(file_path, file_content)
if project.lfs_enabled? && lfs_file?(file_path)
lfs_pointer_file = Gitlab::Git::LfsPointerFile.new(file_content)
lfs_object = create_lfs_object!(lfs_pointer_file, file_content)
content = lfs_pointer_file.pointer
success = yield(content)
link_lfs_object!(lfs_object) if success
else
yield(file_content)
end
end
private
def lfs_file?(file_path)
repository.attributes_at(branch_name, file_path)['filter'] == 'lfs'
end
def create_lfs_object!(lfs_pointer_file, file_content)
LfsObject.find_or_create_by(oid: lfs_pointer_file.sha256, size: lfs_pointer_file.size) do |lfs_object|
lfs_object.file = CarrierWaveStringFile.new(file_content)
end
end
def link_lfs_object!(lfs_object)
project.lfs_objects << lfs_object
end
end
end
......@@ -17,6 +17,8 @@ class FileUploader < GitlabUploader
after :remove, :prune_store_dir
after :remove, :prune_store_dir
def self.root
File.join(options.storage_path, 'uploads')
end
......
......@@ -107,7 +107,11 @@
%strong.fly-out-top-item-name
#{ _('Members') }
- if current_user && can?(current_user, :admin_group, @group)
<<<<<<< HEAD
= nav_link(path: %w[groups#projects groups#edit ci_cd#show ldap_group_links#index hooks#index audit_events#index pipeline_quota#index]) do
=======
= nav_link(path: group_nav_link_paths) do
>>>>>>> upstream/master
= link_to edit_group_path(@group) do
.nav-icon-container
= sprite_icon('settings')
......
......@@ -220,7 +220,7 @@
%p
= _('Protip:')
= link_to 'Auto DevOps', help_page_path('topics/autodevops/index.md')
%span= _('uses clusters to deploy your code!')
%span= _('uses Kubernetes clusters to deploy your code!')
%hr
%button.btn.btn-create.btn-xs.dismiss-feature-highlight{ type: 'button' }
%span= _("Got it!")
......
......@@ -8,7 +8,10 @@
.top-area.adjust
.nav-text
= s_("ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project")
<<<<<<< HEAD
= render 'projects/ee/clusters/buttons', project: @project
=======
>>>>>>> upstream/master
.ci-table.js-clusters-list
.gl-responsive-table-row.table-row-header{ role: "row" }
.table-section.section-30{ role: "rowheader" }
......
......@@ -13,7 +13,8 @@
toggle_status: @cluster.enabled? ? 'true': 'false',
cluster_status: @cluster.status_name,
cluster_status_reason: @cluster.status_reason,
help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications') } }
help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications'),
ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-ip-address') } }
.js-cluster-application-notice
.flash-container
......
.modal{ id: "modal-delete-label-#{label.id}", tabindex: -1 }
.modal-dialog
.modal-content
.modal-header
%button.close{ data: {dismiss: 'modal' } } &times;
%h3.page-title Delete #{render_colored_label(label, tooltip: false)} ?
.modal-body
%p
%strong= label.name
%span will be permanently deleted from #{label.is_a?(ProjectLabel)? label.project.name : label.group.name}. This cannot be undone.
.modal-footer
%a{ href: '#', data: { dismiss: 'modal' }, class: 'btn btn-default' } Cancel
= link_to 'Delete label',
destroy_label_path(label),
title: 'Delete',
method: :delete,
class: 'btn btn-remove'
......@@ -5,10 +5,10 @@
- show_label_merge_requests_link = show_label_issuables_link?(label, :merge_requests, project: @project)
- show_label_issues_link = show_label_issuables_link?(label, :issues, project: @project)
%li{ id: label_css_id, data: { id: label.id } }
%li.label-list-item{ id: label_css_id, data: { id: label.id } }
= render "shared/label_row", label: label
.visible-xs.visible-sm-inline-block.visible-md-inline-block.dropdown
.visible-xs.visible-sm-inline-block.dropdown
%button.btn.btn-default.label-options-toggle{ type: 'button', data: { toggle: "dropdown" } }
Options
= icon('caret-down')
......@@ -46,14 +46,19 @@
data: {confirm: 'Remove this label? Are you sure?'},
class: 'text-danger'
.pull-right.hidden-xs.hidden-sm.hidden-md
- if show_label_merge_requests_link
= link_to_label(label, subject: subject, type: :merge_request, css_class: 'btn btn-transparent btn-action btn-link') do
view merge requests
- if show_label_issues_link
= link_to_label(label, subject: subject, css_class: 'btn btn-transparent btn-action btn-link') do
view open issues
.pull-right.hidden-xs.hidden-sm
- if label.is_a?(ProjectLabel) && label.project.group && can?(current_user, :admin_label, label.project.group)
= link_to promote_project_label_path(label.project, label), title: "Promote to Group Label", class: 'btn btn-transparent btn-action', data: {confirm: "You are about to promote #{label.title} to a group level. This will make this milestone available to all projects inside #{label.project.group.name}. The existing project label will be merged into the group level. This action cannot be reversed.", toggle: "tooltip"}, method: :post do
%span.sr-only Promote to Group
= sprite_icon('level-up')
- if can?(current_user, :admin_label, label)
= link_to edit_label_path(label), title: "Edit", class: 'btn btn-transparent btn-action', data: {toggle: "tooltip"} do
%span.sr-only Edit
= sprite_icon('pencil')
%span{ data: { toggle: 'modal', target: "#modal-delete-label-#{label.id}" } }
= link_to "#", title: "Delete", class: 'btn btn-transparent btn-action remove-row', data: { toggle: "tooltip" } do
%span.sr-only Delete
= sprite_icon('remove')
- if current_user
.label-subscription.inline
- if can_subscribe_to_label_in_different_levels?(label)
......@@ -76,14 +81,4 @@
%span= label_subscription_toggle_button_text(label, @project)
= icon('spinner spin', class: 'label-subscribe-button-loading')
- if label.is_a?(ProjectLabel) && label.project.group && can?(current_user, :admin_label, label.project.group)
= link_to promote_project_label_path(label.project, label), title: "Promote to Group Label", class: 'btn btn-transparent btn-action', data: {confirm: "You are about to promote #{label.title} to a group level. This will make this milestone available to all projects inside #{label.project.group.name}. The existing project label will be merged into the group level. This action cannot be reversed.", toggle: "tooltip"}, method: :post do
%span.sr-only Promote to Group
= icon('level-up')
- if can?(current_user, :admin_label, label)
= link_to edit_label_path(label), title: "Edit", class: 'btn btn-transparent btn-action', data: {toggle: "tooltip"} do
%span.sr-only Edit
= icon('pencil-square-o')
= link_to destroy_label_path(label), title: "Delete", class: 'btn btn-transparent btn-action remove-row', method: :delete, data: {confirm: label_deletion_confirm_text(label), toggle: "tooltip"} do
%span.sr-only Delete
= icon('trash-o')
= render 'shared/delete_label_modal', label: label
- subject = local_assigns[:subject]
- show_label_issues_link = show_label_issuables_link?(label, :issues, project: @project)
- show_label_merge_requests_link = show_label_issuables_link?(label, :merge_requests, project: @project)
%span.label-row
- if can?(current_user, :admin_label, @project)
.draggable-handler
......@@ -13,6 +17,14 @@
- if defined?(@project) && @project.group.present?
%span.label-type
= label.model_name.human.titleize
- if label.description
%span.label-description
= markdown_field(label, :description)
%span.label-description
- if label.description.present?
.description-text
= markdown_field(label, :description)
.hidden-xs.hidden-sm
- if show_label_issues_link
= link_to_label(label, subject: subject) { 'Issues' }
- if show_label_merge_requests_link
&middot;
= link_to_label(label, subject: subject, type: :merge_request) { 'Merge requests' }
......@@ -6,8 +6,11 @@ class BuildFinishedWorker
def perform(build_id)
Ci::Build.find_by(id: build_id).try do |build|
<<<<<<< HEAD
UpdateBuildMinutesService.new(build.project, nil).execute(build)
=======
>>>>>>> upstream/master
# We execute that in sync as this access the files in order to access local file, and reduce IO
BuildTraceSectionsWorker.new.perform(build.id)
BuildCoverageWorker.new.perform(build.id)
......
......@@ -19,6 +19,8 @@ class ProjectCacheWorker
update_statistics(project, statistics.map(&:to_sym))
project.repository.refresh_method_caches(files.map(&:to_sym))
project.cleanup
end
def update_statistics(project, statistics = [])
......
---
title: Add sorting options for /users API (admin only)
merge_request: 16945
author:
type: added
---
title: Add a link to documentation on how to get external ip in the Kubernetes cluster details page
merge_request: 16937
author:
type: added
---
title: Close low level rugged repository in project cache worker
merge_request: 16930
author: Bastian Blank
type: fixed
---
title: Upgrade GitLab Workhorse to v3.6.0
merge_request:
author:
type: other
---
title: Override group sidebar links
merge_request: 16942
author: George Tsiolis
type: fixed
---
title: File Upload UI can create LFS pointers based on .gitattributes
merge_request: 16412
author:
type: fixed
---
title: Downgrade google-protobuf gem
merge_request: 16941
author:
type: other
......@@ -53,6 +53,11 @@ GET /users?blocked=true
GET /users
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `order_by` | string | no | Return projects ordered by `id`, `name`, `username`, `created_at`, or `updated_at` fields. Default is `id` |
| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
```json
[
{
......
......@@ -154,8 +154,8 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
step 'commit has ci status' do
@project.enable_ci
pipeline = create :ci_pipeline, project: @project, sha: sample_commit.id
create :ci_build, pipeline: pipeline
@pipeline = create(:ci_pipeline, project: @project, sha: sample_commit.id)
create(:ci_build, pipeline: @pipeline)
end
step 'repository contains ".gitlab-ci.yml" file' do
......@@ -163,7 +163,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
end
step 'I see commit ci info' do
expect(page).to have_content "Pipeline #1 pending"
expect(page).to have_content "Pipeline ##{@pipeline.id} pending"
end
step 'I search "submodules" commits' do
......
......@@ -15,8 +15,9 @@ class Spinach::Features::ProjectIssuesLabels < Spinach::FeatureSteps
step 'I delete all labels' do
page.within '.labels' do
page.all('.remove-row').each do
accept_confirm { first('.remove-row').click }
page.all('.label-list-item').each do
first('.remove-row').click
first(:link, 'Delete label').click
end
end
end
......
......@@ -18,6 +18,14 @@ module API
User.find_by(id: id) || not_found!('User')
end
def reorder_users(users)
if params[:order_by] && params[:sort]
users.reorder(params[:order_by] => params[:sort])
else
users
end
end
params :optional_attributes do
optional :skype, type: String, desc: 'The Skype username'
optional :linkedin, type: String, desc: 'The LinkedIn username'
......@@ -38,6 +46,13 @@ module API
# EE
optional :shared_runners_minutes_limit, type: Integer, desc: 'Pipeline minutes quota for this user'
end
params :sort_params do
optional :order_by, type: String, values: %w[id name username created_at updated_at],
default: 'id', desc: 'Return users ordered by a field'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return users sorted in ascending and descending order'
end
end
desc 'Get the list of users' do
......@@ -56,19 +71,24 @@ module API
optional :created_before, type: DateTime, desc: 'Return users created before the specified time'
all_or_none_of :extern_uid, :provider
<<<<<<< HEAD
# EE
optional :skip_ldap, type: Boolean, default: false, desc: 'Skip LDAP users'
=======
use :sort_params
>>>>>>> upstream/master
use :pagination
end
get do
authenticated_as_admin! if params[:external].present? || (params[:extern_uid].present? && params[:provider].present?)
unless current_user&.admin?
params.except!(:created_after, :created_before)
params.except!(:created_after, :created_before, :order_by, :sort)
end
users = UsersFinder.new(current_user, params).execute
users = reorder_users(users)
authorized = can?(current_user, :read_users_list)
......
class CarrierWaveStringFile < StringIO
def original_filename
""
end
end
......@@ -15,8 +15,8 @@ module Gitlab
.ancestor?(oldrev, newrev)
else
Gitlab::Git::RevList.new(
path_to_repo: project.repository.path_to_repo,
oldrev: oldrev, newrev: newrev).missed_ref.present?
project.repository.raw, oldrev: oldrev, newrev: newrev
).missed_ref.present?
end
end
end
......
......@@ -25,8 +25,7 @@ module Gitlab
private
def rev_list
::Gitlab::Git::RevList.new(path_to_repo: @repository.path_to_repo,
newrev: @newrev)
Gitlab::Git::RevList.new(@repository, newrev: @newrev)
end
end
end
......
module Gitlab
module Git
class LfsPointerFile
def initialize(data)
@data = data
end
def pointer
@pointer ||= <<~FILE
version https://git-lfs.github.com/spec/v1
oid sha256:#{sha256}
size #{size}
FILE
end
def size
@size ||= @data.bytesize
end
def sha256
@sha256 ||= Digest::SHA256.hexdigest(@data)
end
end
end
end
......@@ -25,7 +25,7 @@ module Gitlab
stdin.close
if lazy_block
return lazy_block.call(stdout.lazy)
return [lazy_block.call(stdout.lazy), 0]
else
cmd_output << stdout.read
end
......
......@@ -128,6 +128,10 @@ module Gitlab
raise NoRepository.new('no repository for such path')
end
def cleanup
@rugged&.close
end
def circuit_breaker
@circuit_breaker ||= Gitlab::Git::Storage::CircuitBreaker.for_storage(storage)
end
......@@ -1427,6 +1431,26 @@ module Gitlab
end
end
def rev_list(including: [], excluding: [], objects: false, &block)
args = ['rev-list']
args.push(*rev_list_param(including))
exclude_param = *rev_list_param(excluding)
if exclude_param.any?
args.push('--not')
args.push(*exclude_param)
end
args.push('--objects') if objects
run_git!(args, lazy_block: block)
end
def missed_ref(oldrev, newrev)
run_git!(['rev-list', '--max-count=1', oldrev, "^#{newrev}"])
end
private
def local_write_ref(ref_path, ref, old_ref: nil, shell: true)
......@@ -1475,7 +1499,7 @@ module Gitlab
Rails.logger.error "Unable to create #{ref_path} reference for repository #{path}: #{ex}"
end
def run_git(args, chdir: path, env: {}, nice: false, &block)
def run_git(args, chdir: path, env: {}, nice: false, lazy_block: nil, &block)
cmd = [Gitlab.config.git.bin_path, *args]
cmd.unshift("nice") if nice
......@@ -1485,12 +1509,12 @@ module Gitlab
end
circuit_breaker.perform do
popen(cmd, chdir, env, &block)
popen(cmd, chdir, env, lazy_block: lazy_block, &block)
end
end
def run_git!(args, chdir: path, env: {}, nice: false, &block)
output, status = run_git(args, chdir: chdir, env: env, nice: nice, &block)
def run_git!(args, chdir: path, env: {}, nice: false, lazy_block: nil, &block)
output, status = run_git(args, chdir: chdir, env: env, nice: nice, lazy_block: lazy_block, &block)
raise GitError, output unless status.zero?
......@@ -2372,6 +2396,10 @@ module Gitlab
rescue Rugged::ReferenceError
0
end
def rev_list_param(spec)
spec == :all ? ['--all'] : spec
end
end
end
end
......@@ -5,17 +5,17 @@ module Gitlab
class RevList
include Gitlab::Git::Popen
attr_reader :oldrev, :newrev, :path_to_repo
attr_reader :oldrev, :newrev, :repository
def initialize(path_to_repo:, newrev:, oldrev: nil)
def initialize(repository, newrev:, oldrev: nil)
@oldrev = oldrev
@newrev = newrev
@path_to_repo = path_to_repo
@repository = repository
end
# This method returns an array of new commit references
def new_refs
execute([*base_args, newrev, '--not', '--all'])
repository.rev_list(including: newrev, excluding: :all).split("\n")
end
# Finds newly added objects
......@@ -28,66 +28,39 @@ module Gitlab
# When given a block it will yield objects as a lazy enumerator so
# the caller can limit work done instead of processing megabytes of data
def new_objects(require_path: nil, not_in: nil, &lazy_block)
args = [*base_args, newrev, *not_in_refs(not_in), '--objects']
opts = {
including: newrev,
excluding: not_in.nil? ? :all : not_in,
require_path: require_path
}
get_objects(args, require_path: require_path, &lazy_block)
get_objects(opts, &lazy_block)
end
def all_objects(require_path: nil, &lazy_block)
args = [*base_args, '--all', '--objects']
get_objects(args, require_path: require_path, &lazy_block)
get_objects(including: :all, require_path: require_path, &lazy_block)
end
# This methods returns an array of missed references
#
# Should become obsolete after https://gitlab.com/gitlab-org/gitaly/issues/348.
def missed_ref
execute([*base_args, '--max-count=1', oldrev, "^#{newrev}"])
repository.missed_ref(oldrev, newrev).split("\n")
end
private
def not_in_refs(references)
return ['--not', '--all'] unless references
return [] if references.empty?
references.prepend('--not')
end
def execute(args)
output, status = popen(args, nil, Gitlab::Git::Env.to_env_hash)
unless status.zero?
raise "Got a non-zero exit code while calling out `#{args.join(' ')}`: #{output}"
end
output.split("\n")
end
def lazy_execute(args, &lazy_block)
popen(args, nil, Gitlab::Git::Env.to_env_hash, lazy_block: lazy_block)
end
def base_args
[
Gitlab.config.git.bin_path,
"--git-dir=#{path_to_repo}",
'rev-list'
]
repository.rev_list(args).split("\n")
end
def get_objects(args, require_path: nil)
if block_given?
lazy_execute(args) do |lazy_output|
objects = objects_from_output(lazy_output, require_path: require_path)
def get_objects(including: [], excluding: [], require_path: nil)
opts = { including: including, excluding: excluding, objects: true }
yield(objects)
end
else
object_output = execute(args)
repository.rev_list(opts) do |lazy_output|
objects = objects_from_output(lazy_output, require_path: require_path)
objects_from_output(object_output, require_path: require_path)
yield(objects)
end
end
......
......@@ -96,11 +96,23 @@ module Gitlab
# :per_page - The number of items per page.
# :limit - Total number of items to return.
def page_versions(page_path, options = {})
current_page = gollum_page_by_path(page_path)
@repository.gitaly_migrate(:wiki_page_versions) do |is_enabled|
if is_enabled
versions = gitaly_wiki_client.page_versions(page_path, options)
# Gitaly uses gollum-lib to get the versions. Gollum defaults to 20
# per page, but also fetches 20 if `limit` or `per_page` < 20.
# Slicing returns an array with the expected number of items.
slice_bound = options[:limit] || options[:per_page] || Gollum::Page.per_page
versions[0..slice_bound]
else
current_page = gollum_page_by_path(page_path)
commits_from_page(current_page, options).map do |gitlab_git_commit|
gollum_page = gollum_wiki.page(current_page.title, gitlab_git_commit.id)
Gitlab::Git::WikiPageVersion.new(gitlab_git_commit, gollum_page&.format)
commits_from_page(current_page, options).map do |gitlab_git_commit|
gollum_page = gollum_wiki.page(current_page.title, gitlab_git_commit.id)
Gitlab::Git::WikiPageVersion.new(gitlab_git_commit, gollum_page&.format)
end
end
end
end
......
......@@ -101,6 +101,30 @@ module Gitlab
pages
end
# options:
# :page - The Integer page number.
# :per_page - The number of items per page.
# :limit - Total number of items to return.
def page_versions(page_path, options)
request = Gitaly::WikiGetPageVersionsRequest.new(
repository: @gitaly_repo,
page_path: encode_binary(page_path),
page: options[:page] || 1,
per_page: options[:per_page] || Gollum::Page.per_page
)
stream = GitalyClient.call(@repository.storage, :wiki_service, :wiki_get_page_versions, request)
versions = []
stream.each do |message|
message.versions.each do |version|
versions << new_wiki_page_version(version)
end
end
versions
end
def find_file(name, revision)
request = Gitaly::WikiFindFileRequest.new(
repository: @gitaly_repo,
......@@ -141,7 +165,7 @@ module Gitlab
private
# If a block is given and the yielded value is true, iteration will be
# If a block is given and the yielded value is truthy, iteration will be
# stopped early at that point; else the iterator is consumed entirely.
# The iterator is traversed with `next` to allow resuming the iteration.
def wiki_page_from_iterator(iterator)
......@@ -158,10 +182,7 @@ module Gitlab
else
wiki_page = GitalyClient::WikiPage.new(page.to_h)
version = Gitlab::Git::WikiPageVersion.new(
Gitlab::Git::Commit.decorate(@repository, page.version.commit),
page.version.format
)
version = new_wiki_page_version(page.version)
end
end
......@@ -170,6 +191,13 @@ module Gitlab
[wiki_page, version]
end
def new_wiki_page_version(version)
Gitlab::Git::WikiPageVersion.new(
Gitlab::Git::Commit.decorate(@repository, version.commit),
version.format
)
end
def gitaly_commit_details(commit_details)
Gitaly::WikiCommitDetails.new(
name: encode_binary(commit_details.name),
......
......@@ -8,8 +8,13 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
<<<<<<< HEAD
"POT-Creation-Date: 2018-02-06 12:32+0100\n"
"PO-Revision-Date: 2018-02-06 12:32+0100\n"
=======
"POT-Creation-Date: 2018-02-06 10:02+0100\n"
"PO-Revision-Date: 2018-02-06 10:02+0100\n"
>>>>>>> upstream/master
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
......@@ -165,9 +170,12 @@ msgstr ""
msgid "All"
msgstr ""
<<<<<<< HEAD
msgid "All changes are committed"
msgstr ""
=======
>>>>>>> upstream/master
msgid "Allows you to add and manage Kubernetes clusters."
msgstr ""
......@@ -177,10 +185,17 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
<<<<<<< HEAD
msgid "An error occurred when updating the issue weight"
msgstr ""
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
=======
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
msgid "An error occurred while fetching markdown preview"
>>>>>>> upstream/master
msgstr ""
msgid "An error occurred while fetching sidebar data"
......@@ -195,12 +210,18 @@ msgstr ""
msgid "An error occurred while rendering KaTeX"
msgstr ""
msgid "An error occurred while rendering preview broadcast message"
msgstr ""
msgid "An error occurred while retrieving calendar activity"
msgstr ""
msgid "An error occurred while retrieving diff"
msgstr ""
msgid "An error occurred while validating username"
msgstr ""
msgid "An error occurred. Please try again."
msgstr ""
......@@ -482,9 +503,12 @@ msgstr ""
msgid "Cannot modify managed Kubernetes cluster"
msgstr ""
<<<<<<< HEAD
msgid "Change Weight"
msgstr ""
=======
>>>>>>> upstream/master
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
......@@ -632,12 +656,15 @@ msgstr ""
msgid "Clone repository"
msgstr ""
<<<<<<< HEAD
msgid "Close"
msgstr ""
msgid "Closed"
msgstr ""
=======
>>>>>>> upstream/master
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
msgstr ""
......@@ -792,9 +819,12 @@ msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to crea
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}"
<<<<<<< HEAD
msgstr ""
msgid "ClusterIntegration|Multiple Kubernetes clusters are available in GitLab Enterprise Edition Premium and Ultimate"
=======
>>>>>>> upstream/master
msgstr ""
msgid "ClusterIntegration|Note:"
......@@ -1681,11 +1711,14 @@ msgstr ""
msgid "Install a Runner compatible with GitLab CI"
msgstr ""
<<<<<<< HEAD
msgid "Instance"
msgid_plural "Instances"
msgstr[0] ""
msgstr[1] ""
=======
>>>>>>> upstream/master
msgid "Instance does not support multiple Kubernetes clusters"
msgstr ""
......@@ -1901,9 +1934,12 @@ msgstr ""
msgid "More information is available|here"
msgstr ""
<<<<<<< HEAD
msgid "Multiple issue boards"
msgstr ""
=======
>>>>>>> upstream/master
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] ""
......@@ -2953,9 +2989,15 @@ msgstr ""
msgid "There are problems accessing Git storage: "
msgstr ""
msgid "There was an error loading users activity calendar."
msgstr ""
msgid "There was an error saving your notification settings."
msgstr ""
msgid "There was an error subscribing to this label."
msgstr ""
msgid "There was an error when reseting email token."
msgstr ""
......@@ -3704,5 +3746,9 @@ msgstr ""
msgid "username"
msgstr ""
<<<<<<< HEAD
msgid "uses clusters to deploy your code!"
=======
msgid "uses Kubernetes clusters to deploy your code!"
>>>>>>> upstream/master
msgstr ""
......@@ -99,7 +99,7 @@ feature 'Prioritize labels' do
expect(page).to have_content 'wontfix'
# Sort labels
drag_to(selector: '.js-prioritized-labels', from_index: 1, to_index: 2)
drag_to(selector: '.label-list-item', from_index: 1, to_index: 2)
page.within('.prioritized-labels') do
expect(first('li')).to have_content('feature')
......
......@@ -71,7 +71,8 @@ describe('Clusters', () => {
helm: { status: APPLICATION_INSTALLABLE, title: 'Helm Tiller' },
});
expect(document.querySelector('.js-cluster-application-notice .flash-text')).toBeNull();
const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text');
expect(flashMessage).toBeNull();
});
it('shows an alert when something gets newly installed', () => {
......@@ -83,8 +84,14 @@ describe('Clusters', () => {
helm: { status: APPLICATION_INSTALLED, title: 'Helm Tiller' },
});
<<<<<<< HEAD
expect(document.querySelector('.js-cluster-application-notice .flash-text')).toBeDefined();
expect(document.querySelector('.js-cluster-application-notice .flash-text').textContent.trim()).toEqual('Helm Tiller was successfully installed on your Kubernetes cluster');
=======
const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text');
expect(flashMessage).not.toBeNull();
expect(flashMessage.textContent.trim()).toEqual('Helm Tiller was successfully installed on your Kubernetes cluster');
>>>>>>> upstream/master
});
it('shows an alert when multiple things gets newly installed', () => {
......@@ -98,8 +105,14 @@ describe('Clusters', () => {
ingress: { status: APPLICATION_INSTALLED, title: 'Ingress' },
});
<<<<<<< HEAD
expect(document.querySelector('.js-cluster-application-notice .flash-text')).toBeDefined();
expect(document.querySelector('.js-cluster-application-notice .flash-text').textContent.trim()).toEqual('Helm Tiller, Ingress was successfully installed on your Kubernetes cluster');
=======
const flashMessage = document.querySelector('.js-cluster-application-notice .flash-text');
expect(flashMessage).not.toBeNull();
expect(flashMessage.textContent.trim()).toEqual('Helm Tiller, Ingress was successfully installed on your Kubernetes cluster');
>>>>>>> upstream/master
});
});
......
......@@ -58,6 +58,7 @@ describe('Clusters Store', () => {
expect(store.state).toEqual({
helpPath: null,
ingressHelpPath: null,
status: mockResponseData.status,
statusReason: mockResponseData.status_reason,
applications: {
......
......@@ -2,18 +2,20 @@ require 'spec_helper'
describe Gitlab::Checks::ForcePush do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository.raw }
context "exit code checking", :skip_gitaly_mock do
it "does not raise a runtime error if the `popen` call to git returns a zero exit code" do
allow_any_instance_of(Gitlab::Git::RevList).to receive(:popen).and_return(['normal output', 0])
allow(repository).to receive(:popen).and_return(['normal output', 0])
expect { described_class.force_push?(project, 'oldrev', 'newrev') }.not_to raise_error
end
it "raises a runtime error if the `popen` call to git returns a non-zero exit code" do
allow_any_instance_of(Gitlab::Git::RevList).to receive(:popen).and_return(['error', 1])
it "raises a GitError error if the `popen` call to git returns a non-zero exit code" do
allow(repository).to receive(:popen).and_return(['error', 1])
expect { described_class.force_push?(project, 'oldrev', 'newrev') }.to raise_error(RuntimeError)
expect { described_class.force_push?(project, 'oldrev', 'newrev') }
.to raise_error(Gitlab::Git::Repository::GitError)
end
end
end
require 'spec_helper'
describe Gitlab::Git::LfsPointerFile do
let(:data) { "1234\n" }
subject { described_class.new(data) }
describe '#size' do
it 'counts the bytes' do
expect(subject.size).to eq 5
end
it 'handles non ascii data' do
expect(described_class.new("ääää").size).to eq 8
end
end
describe '#sha256' do
it 'hashes the content correctly' do
expect(subject.sha256).to eq 'a883dafc480d466ee04e0d6da986bd78eb1fdd2178d04693723da3a8f95d42f4'
end
end
describe '#pointer' do
it 'starts with the LFS version' do
expect(subject.pointer).to start_with('version https://git-lfs.github.com/spec/v1')
end
it 'includes sha256' do
expect(subject.pointer).to match(/^oid sha256:[0-9a-fA-F]{64}/)
end
it 'ends with the size' do
expect(subject.pointer).to end_with("\nsize 5\n")
end
end
end
require 'spec_helper'
describe Gitlab::Git::RevList do
let(:project) { create(:project, :repository) }
let(:rev_list) { described_class.new(newrev: 'newrev', path_to_repo: project.repository.path_to_repo) }
let(:repository) { create(:project, :repository).repository.raw }
let(:rev_list) { described_class.new(repository, newrev: 'newrev') }
let(:env_hash) do
{
'GIT_OBJECT_DIRECTORY' => 'foo',
'GIT_ALTERNATE_OBJECT_DIRECTORIES' => 'bar'
}
end
let(:command_env) { { 'GIT_ALTERNATE_OBJECT_DIRECTORIES' => 'foo:bar' } }
before do
allow(Gitlab::Git::Env).to receive(:all).and_return(env_hash.symbolize_keys)
allow(Gitlab::Git::Env).to receive(:all).and_return(env_hash)
end
def args_for_popen(args_list)
[
Gitlab.config.git.bin_path,
"--git-dir=#{project.repository.path_to_repo}",
'rev-list',
*args_list
]
end
def stub_popen_rev_list(*additional_args, output:)
args = args_for_popen(additional_args)
expect(rev_list).to receive(:popen).with(args, nil, env_hash)
.and_return([output, 0])
[Gitlab.config.git.bin_path, 'rev-list', *args_list]
end
def stub_lazy_popen_rev_list(*additional_args, output:)
def stub_popen_rev_list(*additional_args, with_lazy_block: true, output:)
params = [
args_for_popen(additional_args),
nil,
env_hash,
hash_including(lazy_block: anything)
repository.path,
command_env,
hash_including(lazy_block: with_lazy_block ? anything : nil)
]
expect(rev_list).to receive(:popen).with(*params) do |*_, lazy_block:|
lazy_block.call(output.lines.lazy.map(&:chomp))
expect(repository).to receive(:popen).with(*params) do |*_, lazy_block:|
output = lazy_block.call(output.lines.lazy.map(&:chomp)) if with_lazy_block
[output, 0]
end
end
context "#new_refs" do
it 'calls out to `popen`' do
stub_popen_rev_list('newrev', '--not', '--all', output: "sha1\nsha2")
stub_popen_rev_list('newrev', '--not', '--all', with_lazy_block: false, output: "sha1\nsha2")
expect(rev_list.new_refs).to eq(%w[sha1 sha2])
end
......@@ -55,18 +46,18 @@ describe Gitlab::Git::RevList do
it 'fetches list of newly pushed objects using rev-list' do
stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2")
expect(rev_list.new_objects).to eq(%w[sha1 sha2])
expect { |b| rev_list.new_objects(&b) }.to yield_with_args(%w[sha1 sha2])
end
it 'can skip pathless objects' do
stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2 path/to/file")
expect(rev_list.new_objects(require_path: true)).to eq(%w[sha2])
expect { |b| rev_list.new_objects(require_path: true, &b) }.to yield_with_args(%w[sha2])
end
it 'can handle non utf-8 paths' do
non_utf_char = [0x89].pack("c*").force_encoding("UTF-8")
stub_lazy_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha2 πå†h/†ø/ƒîlé#{non_utf_char}\nsha1")
stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha2 πå†h/†ø/ƒîlé#{non_utf_char}\nsha1")
rev_list.new_objects(require_path: true) do |object_ids|
expect(object_ids.force).to eq(%w[sha2])
......@@ -74,7 +65,7 @@ describe Gitlab::Git::RevList do
end
it 'can yield a lazy enumerator' do
stub_lazy_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2")
stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2")
rev_list.new_objects do |object_ids|
expect(object_ids).to be_a Enumerator::Lazy
......@@ -82,7 +73,7 @@ describe Gitlab::Git::RevList do
end
it 'returns the result of the block when given' do
stub_lazy_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2")
stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2")
objects = rev_list.new_objects do |object_ids|
object_ids.first
......@@ -94,13 +85,13 @@ describe Gitlab::Git::RevList do
it 'can accept list of references to exclude' do
stub_popen_rev_list('newrev', '--not', 'master', '--objects', output: "sha1\nsha2")
expect(rev_list.new_objects(not_in: ['master'])).to eq(%w[sha1 sha2])
expect { |b| rev_list.new_objects(not_in: ['master'], &b) }.to yield_with_args(%w[sha1 sha2])
end
it 'handles empty list of references to exclude as listing all known objects' do
stub_popen_rev_list('newrev', '--objects', output: "sha1\nsha2")
expect(rev_list.new_objects(not_in: [])).to eq(%w[sha1 sha2])
expect { |b| rev_list.new_objects(not_in: [], &b) }.to yield_with_args(%w[sha1 sha2])
end
end
......@@ -108,15 +99,15 @@ describe Gitlab::Git::RevList do
it 'fetches list of all pushed objects using rev-list' do
stub_popen_rev_list('--all', '--objects', output: "sha1\nsha2")
expect(rev_list.all_objects).to eq(%w[sha1 sha2])
expect { |b| rev_list.all_objects(&b) }.to yield_with_args(%w[sha1 sha2])
end
end
context "#missed_ref" do
let(:rev_list) { described_class.new(oldrev: 'oldrev', newrev: 'newrev', path_to_repo: project.repository.path_to_repo) }
let(:rev_list) { described_class.new(repository, oldrev: 'oldrev', newrev: 'newrev') }
it 'calls out to `popen`' do
stub_popen_rev_list('--max-count=1', 'oldrev', '^newrev', output: "sha1\nsha2")
stub_popen_rev_list('--max-count=1', 'oldrev', '^newrev', with_lazy_block: false, output: "sha1\nsha2")
expect(rev_list.missed_ref).to eq(%w[sha1 sha2])
end
......
......@@ -15,6 +15,7 @@ describe Ci::JobArtifact do
it { is_expected.to delegate_method(:open).to(:file) }
it { is_expected.to delegate_method(:exists?).to(:file) }
<<<<<<< HEAD
describe 'callbacks' do
subject { create(:ci_job_artifact, :archive) }
......@@ -73,6 +74,8 @@ describe Ci::JobArtifact do
end
end
=======
>>>>>>> upstream/master
describe '#set_size' do
it 'sets the size' do
expect(artifact.size).to eq(106365)
......
......@@ -412,6 +412,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
context 'if the services is active' do
it 'should return a message' do
expect(kubernetes_service.deprecation_message).to match(/Your Kubernetes cluster information on this page is still editable/)
<<<<<<< HEAD
end
end
......@@ -450,6 +451,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
context 'if the services is active' do
it 'should return a message' do
expect(kubernetes_service.deprecation_message).to match(/Your Kubernetes cluster information on this page is still editable/)
=======
>>>>>>> upstream/master
end
end
......
......@@ -364,18 +364,34 @@ describe WikiPage do
end
describe "#versions" do
before do
create_page("Update", "content")
@page = wiki.find_page("Update")
shared_examples 'wiki page versions' do
let(:page) { wiki.find_page("Update") }
before do
create_page("Update", "content")
end
after do
destroy_page("Update")
end
it "returns an array of all commits for the page" do
3.times { |i| page.update(content: "content #{i}") }
expect(page.versions.count).to eq(4)
end
it 'returns instances of WikiPageVersion' do
expect(page.versions).to all( be_a(Gitlab::Git::WikiPageVersion) )
end
end
after do
destroy_page("Update")
context 'when Gitaly is enabled' do
it_behaves_like 'wiki page versions'
end
it "returns an array of all commits for the page" do
3.times { |i| @page.update(content: "content #{i}") }
expect(@page.versions.count).to eq(4)
context 'when Gitaly is disabled', :disable_gitaly do
it_behaves_like 'wiki page versions'
end
end
......
......@@ -453,6 +453,7 @@ describe API::Jobs do
end
context 'authorized user' do
<<<<<<< HEAD
context 'when trace is in ObjectStorage' do
let!(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
......@@ -469,6 +470,8 @@ describe API::Jobs do
end
end
=======
>>>>>>> upstream/master
context 'when trace is artifact' do
let(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
......
......@@ -199,6 +199,24 @@ describe API::Users do
expect(json_response.size).to eq(1)
expect(json_response.first['username']).to eq(user.username)
end
it 'returns the correct order when sorted by id' do
admin
user
get api('/users', admin), { order_by: 'id', sort: 'asc' }
expect(response).to match_response_schema('public_api/v4/user/admins')
expect(json_response.size).to eq(2)
expect(json_response.first['id']).to eq(admin.id)
expect(json_response.last['id']).to eq(user.id)
end
it 'returns 400 when provided incorrect sort params' do
get api('/users', admin), { order_by: 'magic', sort: 'asc' }
expect(response).to have_gitlab_http_status(400)
end
end
context "when authenticated and ldap is enabled" do
......
require "spec_helper"
describe Files::CreateService do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
let(:file_content) { 'Test file content' }
let(:branch_name) { project.default_branch }
let(:start_branch) { branch_name }
let(:commit_params) do
{
file_path: file_path,
commit_message: "Update File",
file_content: file_content,
file_content_encoding: "text",
start_project: project,
start_branch: start_branch,
branch_name: branch_name
}
end
subject { described_class.new(project, user, commit_params) }
before do
project.add_master(user)
end
describe "#execute" do
context 'when file matches LFS filter' do
let(:file_path) { 'test_file.lfs' }
let(:branch_name) { 'lfs' }
context 'with LFS disabled' do
it 'skips gitattributes check' do
expect(repository).not_to receive(:attributes_at)
subject.execute
end
it "doesn't create LFS pointers" do
subject.execute
blob = repository.blob_at('lfs', file_path)
expect(blob.data).not_to start_with('version https://git-lfs.github.com/spec/v1')
expect(blob.data).to eq(file_content)
end
end
context 'with LFS enabled' do
before do
allow(project).to receive(:lfs_enabled?).and_return(true)
end
it 'creates an LFS pointer' do
subject.execute
blob = repository.blob_at('lfs', file_path)
expect(blob.data).to start_with('version https://git-lfs.github.com/spec/v1')
end
it "creates an LfsObject with the file's content" do
subject.execute
expect(LfsObject.last.file.read).to eq file_content
end
it 'links the LfsObject to the project' do
expect do
subject.execute
end.to change { project.lfs_objects.count }.by(1)
end
end
end
end
end
......@@ -108,7 +108,7 @@ describe MergeRequests::RebaseService do
context 'git commands', :disable_gitaly do
it 'sets GL_REPOSITORY env variable when calling git commands' do
expect(repository).to receive(:popen).exactly(3)
.with(anything, anything, hash_including('GL_REPOSITORY'))
.with(anything, anything, hash_including('GL_REPOSITORY'), anything)
.and_return(['', 0])
service.execute(merge_request)
......
......@@ -59,6 +59,29 @@ describe FileUploader do
end
end
describe 'callbacks' do
describe '#prune_store_dir after :remove' do
before do
uploader.store!(fixture_file_upload('spec/fixtures/doc_sample.txt'))
end
def store_dir
File.expand_path(uploader.store_dir, uploader.root)
end
it 'is called' do
expect(uploader).to receive(:prune_store_dir).once
uploader.remove!
end
it 'prune the store directory' do
expect { uploader.remove! }
.to change { File.exist?(store_dir) }.from(true).to(false)
end
end
end
describe '#secret' do
it 'generates a secret if none is provided' do
expect(described_class).to receive(:generate_secret).and_return('secret')
......
......@@ -12,6 +12,7 @@ describe JobArtifactUploader do
cache_dir: %r[artifacts/tmp/cache],
work_dir: %r[artifacts/tmp/work]
<<<<<<< HEAD
context "object store is REMOTE" do
before do
stub_artifacts_object_storage
......@@ -23,6 +24,8 @@ describe JobArtifactUploader do
store_dir: %r[\h{2}/\h{2}/\h{64}/\d{4}_\d{1,2}_\d{1,2}/\d+/\d+\z]
end
=======
>>>>>>> upstream/master
describe '#open' do
subject { uploader.open }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment