Commit 2a8e7703 authored by Stan Hu's avatar Stan Hu

Merge branch 'ce-to-ee-2018-04-02' into 'master'

CE upstream - 2018-04-02 14:31 UTC

Closes #2262 and gitlab-ce#2262

See merge request gitlab-org/gitlab-ee!5198
parents cdf5a6e3 cc16e553
.project-refs-form,
.project-refs-target-form {
display: inline-block;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.commit-message {
@include str-truncated(250px);
}
.editable-mode {
display: inline-block;
}
.ide-view {
display: flex;
height: calc(100vh - #{$header-height});
margin-top: 40px;
color: $almost-black;
border-top: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
&.is-collapsed {
.ide-file-list {
max-width: 250px;
}
}
.file-status-icon {
width: 10px;
height: 10px;
}
}
.ide-file-list {
flex: 1;
.file {
cursor: pointer;
&.file-open {
background: $white-normal;
}
.ide-file-name {
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
svg {
vertical-align: middle;
margin-right: 2px;
}
.loading-container {
margin-right: 4px;
display: inline-block;
}
}
.ide-file-changed-icon {
margin-left: auto;
}
.ide-new-btn {
display: none;
margin-bottom: -4px;
margin-right: -8px;
}
&:hover {
.ide-new-btn {
display: block;
}
}
&.folder {
svg {
fill: $gl-text-color-secondary;
}
}
}
a {
color: $gl-text-color;
}
th {
position: sticky;
top: 0;
}
}
.file-name,
.file-col-commit-message {
display: flex;
overflow: visible;
padding: 6px 12px;
}
.multi-file-loading-container {
margin-top: 10px;
padding: 10px;
.animation-container {
background: $gray-light;
div {
background: $gray-light;
}
}
}
.multi-file-table-col-commit-message {
white-space: nowrap;
width: 50%;
}
.multi-file-edit-pane {
display: flex;
flex-direction: column;
flex: 1;
border-left: 1px solid $white-dark;
overflow: hidden;
}
.multi-file-tabs {
display: flex;
background-color: $white-normal;
box-shadow: inset 0 -1px $white-dark;
> ul {
display: flex;
overflow-x: auto;
}
li {
position: relative;
}
.dropdown {
display: flex;
margin-left: auto;
margin-bottom: 1px;
padding: 0 $grid-size;
border-left: 1px solid $white-dark;
background-color: $white-light;
&.shadow {
box-shadow: 0 0 10px $dropdown-shadow-color;
}
.btn {
margin-top: auto;
margin-bottom: auto;
}
}
}
.multi-file-tab {
@include str-truncated(150px);
padding: ($gl-padding / 2) ($gl-padding + 12) ($gl-padding / 2) $gl-padding;
background-color: $gray-normal;
border-right: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
cursor: pointer;
svg {
vertical-align: middle;
}
&.active {
background-color: $white-light;
border-bottom-color: $white-light;
}
}
.multi-file-tab-close {
position: absolute;
right: 8px;
top: 50%;
width: 16px;
height: 16px;
padding: 0;
background: none;
border: 0;
border-radius: $border-radius-default;
color: $theme-gray-900;
transform: translateY(-50%);
svg {
position: relative;
top: -1px;
}
&:hover {
background-color: $theme-gray-200;
}
&:focus {
background-color: $blue-500;
color: $white-light;
outline: 0;
svg {
fill: currentColor;
}
}
}
.multi-file-edit-pane-content {
flex: 1;
height: 0;
}
.blob-editor-container {
flex: 1;
height: 0;
display: flex;
flex-direction: column;
justify-content: center;
.vertical-center {
min-height: auto;
}
.monaco-editor .lines-content .cigr {
display: none;
}
.monaco-diff-editor.vs {
.editor.modified {
box-shadow: none;
}
.diagonal-fill {
display: none !important;
}
.diffOverview {
background-color: $white-light;
border-left: 1px solid $white-dark;
cursor: ns-resize;
}
.diffViewport {
display: none;
}
.char-insert {
background-color: $line-added-dark;
}
.char-delete {
background-color: $line-removed-dark;
}
.line-numbers {
color: $black-transparent;
}
.view-overlays {
.line-insert {
background-color: $line-added;
}
.line-delete {
background-color: $line-removed;
}
}
.margin {
background-color: $gray-light;
border-right: 1px solid $white-normal;
.line-insert {
border-right: 1px solid $line-added-dark;
}
.line-delete {
border-right: 1px solid $line-removed-dark;
}
}
.margin-view-overlays .insert-sign,
.margin-view-overlays .delete-sign {
opacity: 0.4;
}
.cursors-layer {
display: none;
}
}
}
.multi-file-editor-holder {
height: 100%;
}
.multi-file-editor-btn-group {
padding: $gl-bar-padding $gl-padding;
border-top: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
background: $white-light;
}
.ide-status-bar {
padding: $gl-bar-padding $gl-padding;
background: $white-light;
display: flex;
justify-content: space-between;
svg {
vertical-align: middle;
}
}
// Not great, but this is to deal with our current output
.multi-file-preview-holder {
height: 100%;
overflow: scroll;
.file-content.code {
display: flex;
i {
margin-left: -10px;
}
}
.line-numbers {
min-width: 50px;
}
.file-content,
.line-numbers,
.blob-content,
.code {
min-height: 100%;
}
}
.file-content.blob-no-preview {
a {
margin-left: auto;
margin-right: auto;
}
}
.multi-file-commit-panel {
display: flex;
position: relative;
flex-direction: column;
width: 340px;
padding: 0;
background-color: $gray-light;
padding-right: 3px;
.projects-sidebar {
display: flex;
flex-direction: column;
.context-header {
width: auto;
margin-right: 0;
}
}
.multi-file-commit-panel-inner {
display: flex;
flex: 1;
flex-direction: column;
}
.multi-file-commit-panel-inner-scroll {
display: flex;
flex: 1;
flex-direction: column;
overflow: auto;
}
&.is-collapsed {
width: 60px;
.multi-file-commit-list {
padding-top: $gl-padding;
overflow: hidden;
}
.multi-file-context-bar-icon {
align-items: center;
svg {
float: none;
margin: 0;
}
}
}
.branch-container {
border-left: 4px solid $indigo-700;
margin-bottom: $gl-bar-padding;
}
.branch-header {
background: $white-dark;
display: flex;
}
.branch-header-title {
flex: 1;
padding: $grid-size $gl-padding;
color: $indigo-700;
font-weight: $gl-font-weight-bold;
svg {
vertical-align: middle;
}
}
.branch-header-btns {
padding: $gl-vert-padding $gl-padding;
}
.left-collapse-btn {
display: none;
background: $gray-light;
text-align: left;
border-top: 1px solid $white-dark;
svg {
vertical-align: middle;
}
}
}
.multi-file-context-bar-icon {
padding: 10px;
svg {
margin-right: 10px;
float: left;
}
}
.multi-file-commit-panel-section {
display: flex;
flex-direction: column;
flex: 1;
}
.multi-file-commit-empty-state-container {
align-items: center;
justify-content: center;
}
.multi-file-commit-panel-header {
display: flex;
align-items: center;
margin-bottom: 12px;
border-bottom: 1px solid $white-dark;
padding: $gl-btn-padding 0;
&.is-collapsed {
border-bottom: 1px solid $white-dark;
svg {
margin-left: auto;
margin-right: auto;
}
.multi-file-commit-panel-collapse-btn {
margin-right: auto;
margin-left: auto;
border-left: 0;
}
}
}
.multi-file-commit-panel-header-title {
display: flex;
flex: 1;
padding: 0 $gl-btn-padding;
svg {
margin-right: $gl-btn-padding;
}
}
.multi-file-commit-panel-collapse-btn {
border-left: 1px solid $white-dark;
}
.multi-file-commit-list {
flex: 1;
overflow: auto;
padding: $gl-padding 0;
min-height: 60px;
}
.multi-file-commit-list-item {
display: flex;
padding: 0;
align-items: center;
.multi-file-discard-btn {
display: none;
margin-left: auto;
color: $gl-link-color;
padding: 0 2px;
&:focus,
&:hover {
text-decoration: underline;
}
}
&:hover {
background: $white-normal;
.multi-file-discard-btn {
display: block;
}
}
}
.multi-file-addition {
fill: $green-500;
}
.multi-file-modified {
fill: $orange-500;
}
.multi-file-commit-list-collapsed {
display: flex;
flex-direction: column;
> svg {
margin-left: auto;
margin-right: auto;
}
.file-status-icon {
width: 10px;
height: 10px;
margin-left: 3px;
}
}
.multi-file-commit-list-path {
padding: $grid-size / 2;
padding-left: $gl-padding;
background: none;
border: 0;
text-align: left;
width: 100%;
min-width: 0;
svg {
min-width: 16px;
vertical-align: middle;
display: inline-block;
}
&:hover,
&:focus {
outline: 0;
}
}
.multi-file-commit-list-file-path {
@include str-truncated(100%);
&:hover {
text-decoration: underline;
}
&:active {
text-decoration: none;
}
}
.multi-file-commit-form {
padding: $gl-padding;
border-top: 1px solid $white-dark;
.btn {
font-size: $gl-font-size;
}
}
.multi-file-commit-message.form-control {
height: 160px;
resize: none;
}
.dirty-diff {
// !important need to override monaco inline style
width: 4px !important;
left: 0 !important;
&-modified {
background-color: $blue-500;
}
&-added {
background-color: $green-600;
}
&-removed {
height: 0 !important;
width: 0 !important;
bottom: -2px;
border-style: solid;
border-width: 5px;
border-color: transparent transparent transparent $red-500;
&::before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 1px;
background-color: rgba($red-500, 0.5);
}
}
}
.ide-loading {
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
}
.ide-empty-state {
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
}
.ide-new-btn {
.dropdown-toggle svg {
margin-top: -2px;
margin-bottom: 2px;
}
.dropdown-menu {
left: auto;
right: 0;
label {
font-weight: $gl-font-weight-normal;
padding: 5px 8px;
margin-bottom: 0;
}
}
}
.ide {
overflow: hidden;
&.nav-only {
.flash-container {
margin-top: $header-height;
margin-bottom: 0;
}
.alert-wrapper .flash-container .flash-alert:last-child,
.alert-wrapper .flash-container .flash-notice:last-child {
margin-bottom: 0;
}
.content-wrapper {
margin-top: $header-height;
padding-bottom: 0;
}
&.flash-shown {
.content-wrapper {
margin-top: 0;
}
.ide-view {
height: calc(100vh - #{$header-height + $flash-height});
}
}
.projects-sidebar {
.multi-file-commit-panel-inner-scroll {
flex: 1;
}
}
}
}
.with-performance-bar .ide.nav-only {
.flash-container {
margin-top: #{$header-height + $performance-bar-height};
}
.content-wrapper {
margin-top: #{$header-height + $performance-bar-height};
padding-bottom: 0;
}
.ide-view {
height: calc(100vh - #{$header-height + $performance-bar-height});
}
&.flash-shown {
.content-wrapper {
margin-top: 0;
}
.ide-view {
height: calc(
100vh - #{$header-height + $performance-bar-height + $flash-height}
);
}
}
}
.dragHandle {
position: absolute;
top: 0;
bottom: 0;
width: 3px;
background-color: $white-dark;
&.dragright {
right: 0;
}
&.dragleft {
left: 0;
}
}
.ide-commit-radios {
label {
font-weight: normal;
}
.help-block {
margin-top: 0;
line-height: 0;
}
}
.ide-commit-new-branch {
margin-left: 25px;
}
.ide-external-links {
p {
margin: 0;
}
}
.ide-sidebar-link {
padding: $gl-padding-8 $gl-padding;
background: $indigo-700;
color: $white-light;
text-decoration: none;
display: flex;
align-items: center;
&:focus,
&:hover {
color: $white-light;
text-decoration: underline;
background: $indigo-500;
}
&:active {
background: $indigo-800;
}
}
......@@ -291,6 +291,10 @@ module ApplicationHelper
class_names
end
# EE feature: System header and footer, unavailable in CE
def system_message_class
end
# Returns active css class when condition returns true
# otherwise returns nil.
#
......
class CertificateFingerprintValidator < ActiveModel::EachValidator
FINGERPRINT_PATTERN = /\A([a-zA-Z0-9]{2}[\s\-:]?){16,}\z/.freeze
def validate_each(record, attribute, value)
unless value.try(:match, FINGERPRINT_PATTERN)
record.errors.add(attribute, "must be a hash containing only letters, numbers, spaces, : and -")
end
end
end
class TopLevelGroupValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if value&.subgroup?
record.errors.add(attribute, "must be a top level Group")
end
end
end
......@@ -138,21 +138,18 @@ module ObjectStorage
include Report
def self.enqueue!(uploads, mounted_as, to_store)
sanity_check!(uploads, mounted_as)
def self.enqueue!(uploads, model_class, mounted_as, to_store)
sanity_check!(uploads, model_class, mounted_as)
perform_async(uploads.ids, mounted_as, to_store)
perform_async(uploads.ids, model_class.to_s, mounted_as, to_store)
end
# We need to be sure all the uploads are for the same uploader and model type
# and that the mount point exists if provided.
#
def self.sanity_check!(uploads, mounted_as)
def self.sanity_check!(uploads, model_class, mounted_as)
upload = uploads.first
uploader_class = upload.uploader.constantize
model_class = uploads.first.model_type.constantize
uploader_types = uploads.map(&:uploader).uniq
model_types = uploads.map(&:model_type).uniq
model_has_mount = mounted_as.nil? || model_class.uploaders[mounted_as] == uploader_class
......@@ -162,7 +159,12 @@ module ObjectStorage
raise(SanityCheckError, "Mount point #{mounted_as} not found in #{model_class}.") unless model_has_mount
end
def perform(ids, mounted_as, to_store)
def perform(*args)
args_check!(args)
(ids, model_type, mounted_as, to_store) = args
@model_class = model_type.constantize
@mounted_as = mounted_as&.to_sym
@to_store = to_store
......@@ -178,7 +180,17 @@ module ObjectStorage
end
def sanity_check!(uploads)
self.class.sanity_check!(uploads, @mounted_as)
self.class.sanity_check!(uploads, @model_class, @mounted_as)
end
def args_check!(args)
return if args.count == 4
case args.count
when 3 then raise SanityCheckError, "Job is missing the `model_type` argument."
else
raise SanityCheckError, "Job has wrong arguments format."
end
end
def build_uploaders(uploads)
......
---
title: Fixed gitlab:uploads:migrate task failing for Groups' avatar.
merge_request: 18088
author:
type: fixed
......@@ -412,9 +412,10 @@ Example response:
Since GitLab 8.1, this is the new commit status API.
### Get the status of a commit
### List the statuses of a commit
Get the statuses of a commit in a project.
List the statuses of a commit in a project.
The pagination parameters `page` and `per_page` can be used to restrict the list of references.
```
GET /projects/:id/repository/commits/:sha/statuses
......
......@@ -46,6 +46,8 @@ module Gitlab
iterator = State.new
@content.split("\n").each_with_object(iterator) do |text, iterator|
text.chomp!
next if text =~ /^\s*#/
if text =~ /\A\[submodule "(?<name>[^"]+)"\]\z/
......@@ -55,7 +57,7 @@ module Gitlab
next unless text =~ /\A\s*(?<key>\w+)\s*=\s*(?<value>.*)\z/
value = $~[:value].chomp
value = $~[:value]
iterator.set_attribute($~[:key], value)
end
end
......
......@@ -13,6 +13,7 @@ namespace :gitlab do
def enqueue_batch(batch, index)
job = ObjectStorage::MigrateUploadsWorker.enqueue!(batch,
@model_class,
@mounted_as,
@to_store)
puts "Enqueued job ##{index}: #{job}"
......
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::Git::GitmodulesParser do
it 'should parse a .gitmodules file correctly' do
parser = described_class.new(<<-'GITMODULES'.strip_heredoc)
data = <<~GITMODULES
[submodule "vendor/libgit2"]
path = vendor/libgit2
[submodule "vendor/libgit2"]
......@@ -16,6 +16,7 @@ describe Gitlab::Git::GitmodulesParser do
url = https://example.com/another/project
GITMODULES
parser = described_class.new(data.gsub("\n", "\r\n"))
modules = parser.parse
expect(modules).to eq({
......
......@@ -2,12 +2,25 @@
#
module CookieHelper
def set_cookie(name, value, options = {})
case page.driver
when Capybara::RackTest::Driver
rack_set_cookie(name, value)
else
selenium_set_cookie(name, value, options)
end
end
def selenium_set_cookie(name, value, options = {})
# Selenium driver will not set cookies for a given domain when the browser is at `about:blank`.
# It also doesn't appear to allow overriding the cookie path. loading `/` is the most inclusive.
visit options.fetch(:path, '/') unless on_a_page?
page.driver.browser.manage.add_cookie(name: name, value: value, **options)
end
def rack_set_cookie(name, value)
page.driver.browser.set_cookie("#{name}=#{value}")
end
def get_cookie(name)
page.driver.browser.manage.cookie_named(name)
end
......
......@@ -140,6 +140,10 @@ module LoginHelpers
end
allow(Gitlab::Auth::OAuth::Provider).to receive_messages(providers: [:saml], config_for: mock_saml_config)
stub_omniauth_setting(messages)
stub_saml_authorize_path_helpers
end
def stub_saml_authorize_path_helpers
allow_any_instance_of(Object).to receive(:user_saml_omniauth_authorize_path).and_return('/users/auth/saml')
allow_any_instance_of(Object).to receive(:omniauth_authorize_path).with(:user, "saml").and_return('/users/auth/saml')
end
......
require 'rake_helper'
describe 'gitlab:uploads:migrate rake tasks' do
let!(:projects) { create_list(:project, 10, :with_avatar) }
let(:model_class) { Project }
let(:uploader_class) { AvatarUploader }
let(:mounted_as) { :avatar }
let(:model_class) { nil }
let(:uploader_class) { nil }
let(:mounted_as) { nil }
let(:batch_size) { 3 }
before do
......@@ -30,11 +29,113 @@ describe 'gitlab:uploads:migrate rake tasks' do
end
end
it_behaves_like 'enqueue jobs in batch', batch: 4
context "for AvatarUploader" do
let(:uploader_class) { AvatarUploader }
let(:mounted_as) { :avatar }
context "for Project" do
let(:model_class) { Project }
let!(:projects) { create_list(:project, 10, :with_avatar) }
it_behaves_like 'enqueue jobs in batch', batch: 4
context 'Upload has store = nil' do
before do
Upload.where(model: projects).update_all(store: nil)
end
it_behaves_like 'enqueue jobs in batch', batch: 4
end
end
context "for Group" do
let(:model_class) { Group }
before do
create_list(:group, 10, :with_avatar)
end
it_behaves_like 'enqueue jobs in batch', batch: 4
end
context "for User" do
let(:model_class) { User }
before do
create_list(:user, 10, :with_avatar)
end
it_behaves_like 'enqueue jobs in batch', batch: 4
end
end
context "for AttachmentUploader" do
let(:uploader_class) { AttachmentUploader }
context "for Note" do
let(:model_class) { Note }
let(:mounted_as) { :attachment }
before do
create_list(:note, 10, :with_attachment)
end
it_behaves_like 'enqueue jobs in batch', batch: 4
end
context "for Appearance" do
let(:model_class) { Appearance }
let(:mounted_as) { :logo }
before do
create(:appearance, :with_logos)
end
%i(logo header_logo).each do |mount|
it_behaves_like 'enqueue jobs in batch', batch: 1 do
let(:mounted_as) { mount }
end
end
end
end
context "for FileUploader" do
let(:uploader_class) { FileUploader }
let(:model_class) { Project }
before do
create_list(:project, 10) do |model|
uploader_class.new(model)
.store!(fixture_file_upload('spec/fixtures/doc_sample.txt'))
end
end
it_behaves_like 'enqueue jobs in batch', batch: 4
end
context "for PersonalFileUploader" do
let(:uploader_class) { PersonalFileUploader }
let(:model_class) { PersonalSnippet }
before do
create_list(:personal_snippet, 10) do |model|
uploader_class.new(model)
.store!(fixture_file_upload('spec/fixtures/doc_sample.txt'))
end
end
it_behaves_like 'enqueue jobs in batch', batch: 4
end
context "for NamespaceFileUploader" do
let(:uploader_class) { NamespaceFileUploader }
let(:model_class) { Snippet }
context 'Upload has store = nil' do
before do
Upload.where(model: projects).update_all(store: nil)
create_list(:snippet, 10) do |model|
uploader_class.new(model)
.store!(fixture_file_upload('spec/fixtures/doc_sample.txt'))
end
end
it_behaves_like 'enqueue jobs in batch', batch: 4
......
......@@ -9,6 +9,7 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do
let!(:projects) { create_list(:project, 10, :with_avatar) }
let(:uploads) { Upload.all }
let(:model_class) { Project }
let(:mounted_as) { :avatar }
let(:to_store) { ObjectStorage::Store::REMOTE }
......@@ -18,7 +19,7 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do
describe '.enqueue!' do
def enqueue!
described_class.enqueue!(uploads, mounted_as, to_store)
described_class.enqueue!(uploads, Project, mounted_as, to_store)
end
it 'is guarded by .sanity_check!' do
......@@ -44,7 +45,7 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do
let(:mount_point) { nil }
it do
expect { described_class.sanity_check!(uploads, mount_point) }
expect { described_class.sanity_check!(uploads, model_class, mount_point) }
.to raise_error(described_class::SanityCheckError)
end
end
......@@ -70,7 +71,7 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do
describe '#perform' do
def perform
described_class.new.perform(uploads.ids, mounted_as, to_store)
described_class.new.perform(uploads.ids, model_class.to_s, mounted_as, to_store)
rescue ObjectStorage::MigrateUploadsWorker::Report::MigrationFailures
# swallow
end
......
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