Commit 669c24d9 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 13076511
......@@ -19,7 +19,7 @@ import { getLocationHash, visitUrl } from './lib/utils/url_utility';
// everything else
import loadAwardsHandler from './awards_handler';
import bp from './breakpoints';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import Flash, { removeFlashClickListener } from './flash';
import './gl_dropdown';
import initTodoToggle from './header';
......@@ -185,7 +185,7 @@ document.addEventListener('DOMContentLoaded', () => {
}
});
if (bootstrapBreakpoint === 'xs') {
if (bootstrapBreakpoint === 'sm' || bootstrapBreakpoint === 'xs') {
const $rightSidebar = $('aside.right-sidebar, .layout-page');
$rightSidebar.removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed');
......@@ -270,7 +270,8 @@ document.addEventListener('DOMContentLoaded', () => {
});
$document.on('breakpoint:change', (e, breakpoint) => {
if (breakpoint === 'sm' || breakpoint === 'xs') {
const breakpointSizes = ['md', 'sm', 'xs'];
if (breakpointSizes.includes(breakpoint)) {
const $gutterIcon = $sidebarGutterToggle.find('i');
if ($gutterIcon.hasClass('fa-angle-double-right')) {
$sidebarGutterToggle.trigger('click');
......
......@@ -21,7 +21,7 @@ module RecordUserLastActivity
return if Gitlab::Database.read_only?
if current_user && current_user.last_activity_on != Date.today
Users::ActivityService.new(current_user, "visited #{request.path}").execute
Users::ActivityService.new(current_user).execute
end
end
end
......@@ -109,7 +109,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
end
def log_user_activity
Users::ActivityService.new(user, 'pull').execute
Users::ActivityService.new(user).execute
end
end
......
......@@ -262,7 +262,7 @@ class SessionsController < Devise::SessionsController
def log_user_activity(user)
login_counter.increment
Users::ActivityService.new(user, 'login').execute
Users::ActivityService.new(user).execute
end
def load_recaptcha
......
......@@ -10,10 +10,13 @@ module Types
graphql_name 'Blob'
field :web_url, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :lfs_oid, GraphQL::STRING_TYPE, null: true, resolve: -> (blob, args, ctx) do # rubocop:disable Graphql/Descriptions
Gitlab::Graphql::Loaders::BatchLfsOidLoader.new(blob.repository, blob.id).find
end
field :web_url, GraphQL::STRING_TYPE, null: true,
description: 'Web URL of the blob'
field :lfs_oid, GraphQL::STRING_TYPE, null: true,
description: 'LFS ID of the blob',
resolve: -> (blob, args, ctx) do
Gitlab::Graphql::Loaders::BatchLfsOidLoader.new(blob.repository, blob.id).find
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
......
......@@ -4,12 +4,18 @@ module Types
module EntryType
include Types::BaseInterface
field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :sha, GraphQL::STRING_TYPE, null: false, description: "Last commit sha for entry", method: :id
field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :type, Tree::TypeEnum, null: false # rubocop:disable Graphql/Descriptions
field :path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :flat_path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
field :id, GraphQL::ID_TYPE, null: false,
description: 'ID of the entry'
field :sha, GraphQL::STRING_TYPE, null: false,
description: 'Last commit sha for the entry', method: :id
field :name, GraphQL::STRING_TYPE, null: false,
description: 'Name of the entry'
field :type, Tree::TypeEnum, null: false,
description: 'Type of tree entry'
field :path, GraphQL::STRING_TYPE, null: false,
description: 'Path of the entry'
field :flat_path, GraphQL::STRING_TYPE, null: false,
description: 'Flat path of the entry'
end
end
end
......@@ -8,8 +8,10 @@ module Types
graphql_name 'Submodule'
field :web_url, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :tree_url, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :web_url, type: GraphQL::STRING_TYPE, null: true,
description: 'Web URL for the sub-module'
field :tree_url, type: GraphQL::STRING_TYPE, null: true,
description: 'Tree URL for the sub-module'
end
# rubocop: enable Graphql/AuthorizeTypes
end
......
......@@ -11,7 +11,8 @@ module Types
graphql_name 'TreeEntry'
description 'Represents a directory'
field :web_url, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
field :web_url, GraphQL::STRING_TYPE, null: true,
description: 'Web URL for the tree entry (directory)'
end
# rubocop: enable Graphql/AuthorizeTypes
end
......
......@@ -11,19 +11,23 @@ module Types
null: true, complexity: 10, calls_gitaly: true, resolver: Resolvers::LastCommitResolver,
description: 'Last commit for the tree'
field :trees, Types::Tree::TreeEntryType.connection_type, null: false, resolve: -> (obj, args, ctx) do # rubocop:disable Graphql/Descriptions
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.trees, obj.repository)
end
field :trees, Types::Tree::TreeEntryType.connection_type, null: false,
description: 'Trees of the tree',
resolve: -> (obj, args, ctx) do
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.trees, obj.repository)
end
# rubocop:disable Graphql/Descriptions
field :submodules, Types::Tree::SubmoduleType.connection_type, null: false, calls_gitaly: true, resolve: -> (obj, args, ctx) do
Gitlab::Graphql::Representation::SubmoduleTreeEntry.decorate(obj.submodules, obj)
end
# rubocop:enable Graphql/Descriptions
field :submodules, Types::Tree::SubmoduleType.connection_type, null: false,
description: 'Sub-modules of the tree',
calls_gitaly: true, resolve: -> (obj, args, ctx) do
Gitlab::Graphql::Representation::SubmoduleTreeEntry.decorate(obj.submodules, obj)
end
field :blobs, Types::Tree::BlobType.connection_type, null: false, calls_gitaly: true, resolve: -> (obj, args, ctx) do # rubocop:disable Graphql/Descriptions
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.blobs, obj.repository)
end
field :blobs, Types::Tree::BlobType.connection_type, null: false,
description: 'Blobs of the tree',
calls_gitaly: true, resolve: -> (obj, args, ctx) do
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.blobs, obj.repository)
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
......
......@@ -1318,7 +1318,7 @@ class Project < ApplicationRecord
end
def has_active_hooks?(hooks_scope = :push_hooks)
hooks.hooks_for(hooks_scope).any? || SystemHook.hooks_for(hooks_scope).any?
hooks.hooks_for(hooks_scope).any? || SystemHook.hooks_for(hooks_scope).any? || Gitlab::Plugin.any?
end
def has_active_services?(hooks_scope = :push_hooks)
......
......@@ -101,7 +101,7 @@ class EventCreateService
Users::LastPushEventService.new(current_user)
.cache_last_push_event(event)
Users::ActivityService.new(current_user, 'push').execute
Users::ActivityService.new(current_user).execute
end
def create_event(resource_parent, current_user, status, attributes = {})
......
......@@ -4,7 +4,7 @@ module Users
class ActivityService
LEASE_TIMEOUT = 1.minute.to_i
def initialize(author, activity)
def initialize(author)
@user = if author.respond_to?(:username)
author
elsif author.respond_to?(:user)
......@@ -12,7 +12,6 @@ module Users
end
@user = nil unless @user.is_a?(User)
@activity = activity
end
def execute
......
---
title: Fix GitLab plugins not working without hooks configured
merge_request: 22409
author:
type: fixed
......@@ -71,17 +71,44 @@ type AwardEmoji {
}
type Blob implements Entry {
"""
Flat path of the entry
"""
flatPath: String!
"""
ID of the entry
"""
id: ID!
"""
LFS ID of the blob
"""
lfsOid: String
"""
Name of the entry
"""
name: String!
"""
Path of the entry
"""
path: String!
"""
Last commit sha for entry
Last commit sha for the entry
"""
sha: String!
"""
Type of tree entry
"""
type: EntryType!
"""
Web URL of the blob
"""
webUrl: String
}
......@@ -1290,15 +1317,34 @@ type DiscussionEdge {
}
interface Entry {
"""
Flat path of the entry
"""
flatPath: String!
"""
ID of the entry
"""
id: ID!
"""
Name of the entry
"""
name: String!
"""
Path of the entry
"""
path: String!
"""
Last commit sha for entry
Last commit sha for the entry
"""
sha: String!
"""
Type of tree entry
"""
type: EntryType!
}
......@@ -5857,17 +5903,44 @@ type SnippetPermissions {
}
type Submodule implements Entry {
"""
Flat path of the entry
"""
flatPath: String!
"""
ID of the entry
"""
id: ID!
"""
Name of the entry
"""
name: String!
"""
Path of the entry
"""
path: String!
"""
Last commit sha for entry
Last commit sha for the entry
"""
sha: String!
"""
Tree URL for the sub-module
"""
treeUrl: String
"""
Type of tree entry
"""
type: EntryType!
"""
Web URL for the sub-module
"""
webUrl: String
}
......@@ -6256,6 +6329,9 @@ type ToggleAwardEmojiPayload {
}
type Tree {
"""
Blobs of the tree
"""
blobs(
"""
Returns the elements in the list that come after the specified cursor.
......@@ -6282,6 +6358,10 @@ type Tree {
Last commit for the tree
"""
lastCommit: Commit
"""
Sub-modules of the tree
"""
submodules(
"""
Returns the elements in the list that come after the specified cursor.
......@@ -6303,6 +6383,10 @@ type Tree {
"""
last: Int
): SubmoduleConnection!
"""
Trees of the tree
"""
trees(
"""
Returns the elements in the list that come after the specified cursor.
......@@ -6330,16 +6414,39 @@ type Tree {
Represents a directory
"""
type TreeEntry implements Entry {
"""
Flat path of the entry
"""
flatPath: String!
"""
ID of the entry
"""
id: ID!
"""
Name of the entry
"""
name: String!
"""
Path of the entry
"""
path: String!
"""
Last commit sha for entry
Last commit sha for the entry
"""
sha: String!
"""
Type of tree entry
"""
type: EntryType!
"""
Web URL for the tree entry (directory)
"""
webUrl: String
}
......
......@@ -11428,7 +11428,7 @@
"fields": [
{
"name": "blobs",
"description": null,
"description": "Blobs of the tree",
"args": [
{
"name": "after",
......@@ -11499,7 +11499,7 @@
},
{
"name": "submodules",
"description": null,
"description": "Sub-modules of the tree",
"args": [
{
"name": "after",
......@@ -11556,7 +11556,7 @@
},
{
"name": "trees",
"description": null,
"description": "Trees of the tree",
"args": [
{
"name": "after",
......@@ -12693,7 +12693,7 @@
"fields": [
{
"name": "flatPath",
"description": null,
"description": "Flat path of the entry",
"args": [
],
......@@ -12711,7 +12711,7 @@
},
{
"name": "id",
"description": null,
"description": "ID of the entry",
"args": [
],
......@@ -12729,7 +12729,7 @@
},
{
"name": "name",
"description": null,
"description": "Name of the entry",
"args": [
],
......@@ -12747,7 +12747,7 @@
},
{
"name": "path",
"description": null,
"description": "Path of the entry",
"args": [
],
......@@ -12765,7 +12765,7 @@
},
{
"name": "sha",
"description": "Last commit sha for entry",
"description": "Last commit sha for the entry",
"args": [
],
......@@ -12783,7 +12783,7 @@
},
{
"name": "type",
"description": null,
"description": "Type of tree entry",
"args": [
],
......@@ -12801,7 +12801,7 @@
},
{
"name": "webUrl",
"description": null,
"description": "Web URL for the tree entry (directory)",
"args": [
],
......@@ -12832,7 +12832,7 @@
"fields": [
{
"name": "flatPath",
"description": null,
"description": "Flat path of the entry",
"args": [
],
......@@ -12850,7 +12850,7 @@
},
{
"name": "id",
"description": null,
"description": "ID of the entry",
"args": [
],
......@@ -12868,7 +12868,7 @@
},
{
"name": "name",
"description": null,
"description": "Name of the entry",
"args": [
],
......@@ -12886,7 +12886,7 @@
},
{
"name": "path",
"description": null,
"description": "Path of the entry",
"args": [
],
......@@ -12904,7 +12904,7 @@
},
{
"name": "sha",
"description": "Last commit sha for entry",
"description": "Last commit sha for the entry",
"args": [
],
......@@ -12922,7 +12922,7 @@
},
{
"name": "type",
"description": null,
"description": "Type of tree entry",
"args": [
],
......@@ -13108,7 +13108,7 @@
"fields": [
{
"name": "flatPath",
"description": null,
"description": "Flat path of the entry",
"args": [
],
......@@ -13126,7 +13126,7 @@
},
{
"name": "id",
"description": null,
"description": "ID of the entry",
"args": [
],
......@@ -13144,7 +13144,7 @@
},
{
"name": "name",
"description": null,
"description": "Name of the entry",
"args": [
],
......@@ -13162,7 +13162,7 @@
},
{
"name": "path",
"description": null,
"description": "Path of the entry",
"args": [
],
......@@ -13180,7 +13180,7 @@
},
{
"name": "sha",
"description": "Last commit sha for entry",
"description": "Last commit sha for the entry",
"args": [
],
......@@ -13198,7 +13198,7 @@
},
{
"name": "treeUrl",
"description": null,
"description": "Tree URL for the sub-module",
"args": [
],
......@@ -13212,7 +13212,7 @@
},
{
"name": "type",
"description": null,
"description": "Type of tree entry",
"args": [
],
......@@ -13230,7 +13230,7 @@
},
{
"name": "webUrl",
"description": null,
"description": "Web URL for the sub-module",
"args": [
],
......@@ -13373,7 +13373,7 @@
"fields": [
{
"name": "flatPath",
"description": null,
"description": "Flat path of the entry",
"args": [
],
......@@ -13391,7 +13391,7 @@
},
{
"name": "id",
"description": null,
"description": "ID of the entry",
"args": [
],
......@@ -13409,7 +13409,7 @@
},
{
"name": "lfsOid",
"description": null,
"description": "LFS ID of the blob",
"args": [
],
......@@ -13423,7 +13423,7 @@
},
{
"name": "name",
"description": null,
"description": "Name of the entry",
"args": [
],
......@@ -13441,7 +13441,7 @@
},
{
"name": "path",
"description": null,
"description": "Path of the entry",
"args": [
],
......@@ -13459,7 +13459,7 @@
},
{
"name": "sha",
"description": "Last commit sha for entry",
"description": "Last commit sha for the entry",
"args": [
],
......@@ -13477,7 +13477,7 @@
},
{
"name": "type",
"description": null,
"description": "Type of tree entry",
"args": [
],
......@@ -13495,7 +13495,7 @@
},
{
"name": "webUrl",
"description": null,
"description": "Web URL of the blob",
"args": [
],
......
......@@ -35,14 +35,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `id` | ID! | |
| `sha` | String! | Last commit sha for entry |
| `name` | String! | |
| `type` | EntryType! | |
| `path` | String! | |
| `flatPath` | String! | |
| `webUrl` | String | |
| `lfsOid` | String | |
| `id` | ID! | ID of the entry |
| `sha` | String! | Last commit sha for the entry |
| `name` | String! | Name of the entry |
| `type` | EntryType! | Type of tree entry |
| `path` | String! | Path of the entry |
| `flatPath` | String! | Flat path of the entry |
| `webUrl` | String | Web URL of the blob |
| `lfsOid` | String | LFS ID of the blob |
### Commit
......@@ -856,14 +856,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `id` | ID! | |
| `sha` | String! | Last commit sha for entry |
| `name` | String! | |
| `type` | EntryType! | |
| `path` | String! | |
| `flatPath` | String! | |
| `webUrl` | String | |
| `treeUrl` | String | |
| `id` | ID! | ID of the entry |
| `sha` | String! | Last commit sha for the entry |
| `name` | String! | Name of the entry |
| `type` | EntryType! | Type of tree entry |
| `path` | String! | Path of the entry |
| `flatPath` | String! | Flat path of the entry |
| `webUrl` | String | Web URL for the sub-module |
| `treeUrl` | String | Tree URL for the sub-module |
### TaskCompletionStatus
......@@ -938,13 +938,13 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `id` | ID! | |
| `sha` | String! | Last commit sha for entry |
| `name` | String! | |
| `type` | EntryType! | |
| `path` | String! | |
| `flatPath` | String! | |
| `webUrl` | String | |
| `id` | ID! | ID of the entry |
| `sha` | String! | Last commit sha for the entry |
| `name` | String! | Name of the entry |
| `type` | EntryType! | Type of tree entry |
| `path` | String! | Path of the entry |
| `flatPath` | String! | Flat path of the entry |
| `webUrl` | String | Web URL for the tree entry (directory) |
### UpdateEpicPayload
......
......@@ -52,7 +52,7 @@ module API
def log_user_activity(actor)
commands = Gitlab::GitAccess::DOWNLOAD_COMMANDS
::Users::ActivityService.new(actor, 'Git SSH').execute if commands.include?(params[:action])
::Users::ActivityService.new(actor).execute if commands.include?(params[:action])
end
def merge_request_urls
......
......@@ -2,10 +2,16 @@
module Gitlab
module Plugin
def self.any?
plugin_glob.any? { |entry| File.file?(entry) }
end
def self.files
Dir.glob(Rails.root.join('plugins/*')).select do |entry|
File.file?(entry)
end
plugin_glob.select { |entry| File.file?(entry) }
end
def self.plugin_glob
Dir.glob(Rails.root.join('plugins/*'))
end
def self.execute_all_async(data)
......
......@@ -3,6 +3,8 @@
require 'spec_helper'
describe Projects::GitHttpController do
include GitHttpHelpers
let_it_be(:project) { create(:project, :public, :repository) }
let(:project_params) do
{
......@@ -31,6 +33,28 @@ describe Projects::GitHttpController do
expect(response.status).to eq(401)
end
context 'with authorized user' do
let(:user) { project.owner }
before do
request.headers.merge! auth_env(user.username, user.password, nil)
end
it 'returns 200' do
get :info_refs, params: params
expect(response.status).to eq(200)
end
it 'updates the user activity' do
expect_next_instance_of(Users::ActivityService) do |activity_service|
expect(activity_service).to receive(:execute)
end
get :info_refs, params: params
end
end
context 'with exceptions' do
before do
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
......
......@@ -3,22 +3,59 @@
require 'spec_helper'
describe Gitlab::Plugin do
let(:plugin) { Rails.root.join('plugins', 'test.rb') }
let(:tmp_file) { Tempfile.new('plugin-dump') }
let(:plugin_source) do
<<~EOS
#!/usr/bin/env ruby
x = STDIN.read
File.write('#{tmp_file.path}', x)
EOS
end
context 'with plugins present' do
before do
File.write(plugin, plugin_source)
end
after do
FileUtils.rm(plugin)
end
describe '.any?' do
it 'returns true' do
expect(described_class.any?).to be true
end
end
describe '.files?' do
it 'returns a list of plugins' do
expect(described_class.files).to match_array([plugin.to_s])
end
end
end
context 'without any plugins' do
describe '.any?' do
it 'returns false' do
expect(described_class.any?).to be false
end
end
describe '.files' do
it 'returns an empty list' do
expect(described_class.files).to be_empty
end
end
end
describe '.execute' do
let(:data) { Gitlab::DataBuilder::Push::SAMPLE_DATA }
let(:plugin) { Rails.root.join('plugins', 'test.rb') }
let(:tmp_file) { Tempfile.new('plugin-dump') }
let(:result) { described_class.execute(plugin.to_s, data) }
let(:success) { result.first }
let(:message) { result.last }
let(:plugin_source) do
<<~EOS
#!/usr/bin/env ruby
x = STDIN.read
File.write('#{tmp_file.path}', x)
EOS
end
before do
File.write(plugin, plugin_source)
end
......
......@@ -4721,6 +4721,13 @@ describe Project do
expect(project.has_active_hooks?(:merge_request_events)).to be_falsey
expect(project.has_active_hooks?).to be_truthy
end
it 'returns true when a plugin exists' do
expect(Gitlab::Plugin).to receive(:any?).twice.and_return(true)
expect(project.has_active_hooks?(:merge_request_events)).to be_truthy
expect(project.has_active_hooks?).to be_truthy
end
end
describe '#has_active_services?' do
......
......@@ -7,7 +7,7 @@ describe Users::ActivityService do
let(:user) { create(:user, last_activity_on: last_activity_on) }
subject { described_class.new(user, 'type') }
subject { described_class.new(user) }
describe '#execute', :clean_gitlab_redis_shared_state do
context 'when last activity is nil' do
......@@ -40,7 +40,7 @@ describe Users::ActivityService do
let(:fake_object) { double(username: 'hello') }
it 'does not record activity' do
service = described_class.new(fake_object, 'pull')
service = described_class.new(fake_object)
expect(service).not_to receive(:record_activity)
......
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