Skip to content
Snippets Groups Projects
Commit b4e0be60 authored by Marcia Ramos's avatar Marcia Ramos
Browse files

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into...

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into 33329-tech-article-deploying-maven-artifacts
parents 06785f92 05151f76
No related branches found
No related tags found
No related merge requests found
Showing
with 174 additions and 67 deletions
export default class GpgBadges {
static fetch() {
const badges = $('.js-loading-gpg-badge');
const form = $('.commits-search-form');
 
badges.html('<i class="fa fa-spinner fa-spin"></i>');
$.get({
url: form.data('signatures-path'),
data: form.serialize(),
}).done((response) => {
const badges = $('.js-loading-gpg-badge');
response.signatures.forEach((signature) => {
badges.filter(`[data-commit-sha="${signature.commit_sha}"]`).replaceWith(signature.html);
});
Loading
Loading
import Vue from 'vue';
import Cookies from 'js-cookie';
import Translate from '../../vue_shared/translate';
import illustrationSvg from '../icons/intro_illustration.svg';
Vue.use(Translate);
const cookieKey = 'pipeline_schedules_callout_dismissed';
export default {
name: 'PipelineSchedulesCallout',
data() {
return {
docsUrl: document.getElementById('pipeline-schedules-callout').dataset.docsUrl,
illustrationSvg,
calloutDismissed: Cookies.get(cookieKey) === 'true',
};
},
methods: {
dismissCallout() {
this.calloutDismissed = true;
Cookies.set(cookieKey, this.calloutDismissed, { expires: 365 });
},
},
template: `
<div v-if="!calloutDismissed" class="pipeline-schedules-user-callout user-callout">
<div class="bordered-box landing content-block">
<button
id="dismiss-callout-btn"
class="btn btn-default close"
@click="dismissCallout">
<i class="fa fa-times"></i>
</button>
<div class="svg-container" v-html="illustrationSvg"></div>
<div class="user-callout-copy">
<h4>{{ __('Scheduling Pipelines') }}</h4>
<p>
{{ __('The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user.') }}
</p>
<p> {{ __('Learn more in the') }}
<a
:href="docsUrl"
target="_blank"
rel="nofollow">{{ s__('Learn more in the|pipeline schedules documentation') }}</a>. <!-- oneline to prevent extra space before period -->
</p>
</div>
</div>
</div>
`,
};
<script>
import Vue from 'vue';
import Cookies from 'js-cookie';
import Translate from '../../vue_shared/translate';
import illustrationSvg from '../icons/intro_illustration.svg';
Vue.use(Translate);
const cookieKey = 'pipeline_schedules_callout_dismissed';
export default {
name: 'PipelineSchedulesCallout',
data() {
return {
docsUrl: document.getElementById('pipeline-schedules-callout').dataset.docsUrl,
calloutDismissed: Cookies.get(cookieKey) === 'true',
};
},
methods: {
dismissCallout() {
this.calloutDismissed = true;
Cookies.set(cookieKey, this.calloutDismissed, { expires: 365 });
},
},
created() {
this.illustrationSvg = illustrationSvg;
},
};
</script>
<template>
<div
v-if="!calloutDismissed"
class="pipeline-schedules-user-callout user-callout">
<div class="bordered-box landing content-block">
<button
id="dismiss-callout-btn"
class="btn btn-default close"
@click="dismissCallout">
<i
aria-hidden="true"
class="fa fa-times">
</i>
</button>
<div class="svg-container" v-html="illustrationSvg"></div>
<div class="user-callout-copy">
<h4>{{ __('Scheduling Pipelines') }}</h4>
<p>
{{ __('The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user.') }}
</p>
<p> {{ __('Learn more in the') }}
<a
:href="docsUrl"
target="_blank"
rel="nofollow">{{ s__('Learn more in the|pipeline schedules documentation') }}</a>. <!-- oneline to prevent extra space before period -->
</p>
</div>
</div>
</div>
</template>
import Vue from 'vue';
import PipelineSchedulesCallout from './components/pipeline_schedules_callout';
import PipelineSchedulesCallout from './components/pipeline_schedules_callout.vue';
 
document.addEventListener('DOMContentLoaded', () => new Vue({
el: '#pipeline-schedules-callout',
Loading
Loading
Loading
Loading
@@ -71,7 +71,7 @@ export default {
/>
<div v-if="!isConfidential" class="no-value confidential-value">
<i class="fa fa-eye is-not-confidential"></i>
None
This issue is not confidential
</div>
<div v-else class="value confidential-value hide-collapsed">
<i aria-hidden="true" data-hidden="true" class="fa fa-eye-slash is-confidential"></i>
Loading
Loading
Loading
Loading
@@ -403,6 +403,7 @@ header.navbar-gitlab-new {
}
 
.breadcrumbs-extra {
display: flex;
flex: 0 0 auto;
margin-left: auto;
}
Loading
Loading
Loading
Loading
@@ -286,6 +286,10 @@
 
 
.gpg-status-box {
&:empty {
display: none;
}
&.valid {
@include green-status-color;
}
Loading
Loading
Loading
Loading
@@ -234,6 +234,8 @@ module ProjectsHelper
# If no limit is applied we'll just issue a COUNT since the result set could
# be too large to load into memory.
def any_projects?(projects)
return projects.any? if projects.is_a?(Array)
if projects.limit_value
projects.to_a.any?
else
Loading
Loading
Loading
Loading
@@ -11,11 +11,11 @@ module Emails
@member_source_type = member_source_type
@member_id = member_id
 
admins = member_source.members.owners_and_masters.includes(:user).pluck(:notification_email)
admins = member_source.members.owners_and_masters.pluck(:notification_email)
# A project in a group can have no explicit owners/masters, in that case
# we fallbacks to the group's owners/masters.
if admins.empty? && member_source.respond_to?(:group) && member_source.group
admins = member_source.group.members.owners_and_masters.includes(:user).pluck(:notification_email)
admins = member_source.group.members.owners_and_masters.pluck(:notification_email)
end
 
mail(to: admins,
Loading
Loading
Loading
Loading
@@ -212,21 +212,39 @@ class Group < Namespace
end
 
def user_ids_for_project_authorizations
users_with_parents.pluck(:id)
members_with_parents.pluck(:user_id)
end
 
def members_with_parents
GroupMember.active.where(source_id: ancestors.pluck(:id).push(id)).where.not(user_id: nil)
# Avoids an unnecessary SELECT when the group has no parents
source_ids =
if parent_id
self_and_ancestors.reorder(nil).select(:id)
else
id
end
GroupMember
.active_without_invites
.where(source_id: source_ids)
end
def members_with_descendants
GroupMember
.active_without_invites
.where(source_id: self_and_descendants.reorder(nil).select(:id))
end
 
def users_with_parents
User.where(id: members_with_parents.select(:user_id))
User
.where(id: members_with_parents.select(:user_id))
.reorder(nil)
end
 
def users_with_descendants
members_with_descendants = GroupMember.non_request.where(source_id: descendants.pluck(:id).push(id))
User.where(id: members_with_descendants.select(:user_id))
User
.where(id: members_with_descendants.select(:user_id))
.reorder(nil)
end
 
def max_member_access_for_user(user)
Loading
Loading
Loading
Loading
@@ -41,9 +41,20 @@ class Member < ActiveRecord::Base
is_external_invite = arel_table[:user_id].eq(nil).and(arel_table[:invite_token].not_eq(nil))
user_is_active = User.arel_table[:state].eq(:active)
 
includes(:user).references(:users)
.where(is_external_invite.or(user_is_active))
user_ok = Arel::Nodes::Grouping.new(is_external_invite).or(user_is_active)
left_join_users
.where(user_ok)
.where(requested_at: nil)
.reorder(nil)
end
# Like active, but without invites. For when a User is required.
scope :active_without_invites, -> do
left_join_users
.where(users: { state: 'active' })
.where(requested_at: nil)
.reorder(nil)
end
 
scope :invite, -> { where.not(invite_token: nil) }
Loading
Loading
Loading
Loading
@@ -156,6 +156,14 @@ class Namespace < ActiveRecord::Base
.base_and_ancestors
end
 
def self_and_ancestors
return self.class.where(id: id) unless parent_id
Gitlab::GroupHierarchy
.new(self.class.where(id: id))
.base_and_ancestors
end
# Returns all the descendants of the current namespace.
def descendants
Gitlab::GroupHierarchy
Loading
Loading
@@ -163,6 +171,12 @@ class Namespace < ActiveRecord::Base
.base_and_descendants
end
 
def self_and_descendants
Gitlab::GroupHierarchy
.new(self.class.where(id: id))
.base_and_descendants
end
def user_ids_for_project_authorizations
[owner_id]
end
Loading
Loading
Loading
Loading
@@ -196,7 +196,6 @@ class Project < ActiveRecord::Base
accepts_nested_attributes_for :import_data
 
delegate :name, to: :owner, allow_nil: true, prefix: true
delegate :count, to: :forks, prefix: true
delegate :members, to: :team, prefix: true
delegate :add_user, :add_users, to: :team
delegate :add_guest, :add_reporter, :add_developer, :add_master, to: :team
Loading
Loading
@@ -1396,6 +1395,10 @@ class Project < ActiveRecord::Base
# @deprecated cannot remove yet because it has an index with its name in elasticsearch
alias_method :path_with_namespace, :full_path
 
def forks_count
Projects::ForksCountService.new(self).count
end
private
 
def cross_namespace_reference?(from)
Loading
Loading
Loading
Loading
@@ -128,6 +128,8 @@ module Projects
project.repository.before_delete
 
Repository.new(wiki_path, project, disk_path: repo_path).before_delete
Projects::ForksCountService.new(project).delete_cache
end
end
end
Loading
Loading
@@ -21,11 +21,17 @@ module Projects
builds_access_level = @project.project_feature.builds_access_level
new_project.project_feature.update_attributes(builds_access_level: builds_access_level)
 
refresh_forks_count
new_project
end
 
private
 
def refresh_forks_count
Projects::ForksCountService.new(@project).refresh_cache
end
def allowed_visibility_level
project_level = @project.visibility_level
 
Loading
Loading
module Projects
# Service class for getting and caching the number of forks of a project.
class ForksCountService
def initialize(project)
@project = project
end
def count
Rails.cache.fetch(cache_key) { uncached_count }
end
def refresh_cache
Rails.cache.write(cache_key, uncached_count)
end
def delete_cache
Rails.cache.delete(cache_key)
end
private
def uncached_count
@project.forks.count
end
def cache_key
['projects', @project.id, 'forks_count']
end
end
end
Loading
Loading
@@ -13,7 +13,13 @@ module Projects
::MergeRequests::CloseService.new(@project, @current_user).execute(mr)
end
 
refresh_forks_count(@project.forked_from_project)
@project.forked_project_link.destroy
end
def refresh_forks_count(project)
Projects::ForksCountService.new(project).refresh_cache
end
end
end
- if commit.has_signature?
%button{ class: commit_signature_badge_classes('js-loading-gpg-badge'), data: { toggle: 'tooltip', placement: 'auto top', title: 'GPG signature (loading...)', 'commit-sha' => commit.sha } }
%i.fa.fa-spinner.fa-spin
= link_to params.merge(rss_url_options), class: 'btn btn-default append-right-10 has-tooltip', title: 'Subscribe' do
= icon('rss')
- if @can_bulk_update
= button_tag "Edit Issues", class: "btn btn-default append-right-10 js-bulk-update-toggle"
= button_tag "Edit issues", class: "btn btn-default append-right-10 js-bulk-update-toggle"
= link_to "New issue", new_project_issue_path(@project,
issue: { assignee_id: issues_finder.assignee.try(:id),
milestone_id: issues_finder.milestones.first.try(:id) }),
Loading
Loading
- if @can_bulk_update
= button_tag "Edit Merge Requests", class: "btn js-bulk-update-toggle"
= button_tag "Edit merge requests", class: "btn append-right-10 js-bulk-update-toggle"
- if merge_project
= link_to new_merge_request_path, class: "btn btn-new", title: "New merge request" do
New merge request
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment