...
 
Commits (127)
......@@ -240,9 +240,6 @@ stages:
- cp ${EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
- scripts/gitaly-test-spawn
- knapsack rspec "-Ispec --color --format documentation --format RspecJunitFormatter --out junit_rspec.xml --tag ~geo"
artifacts:
reports:
junit: junit_rspec.xml
.rspec-ee-pg: &rspec-ee-pg
<<: *rspec-metadata-ee
......@@ -262,9 +259,6 @@ stages:
- source scripts/prepare_postgres_fdw.sh
- scripts/gitaly-test-spawn
- bundle exec rspec --color --format documentation --format RspecJunitFormatter --out junit_rspec.xml --tag geo ee/spec/
artifacts:
reports:
junit: junit_rspec.xml
.rspec-geo-pg-10-2: &rspec-metadata-pg-geo-10-2
<<: *rspec-metadata
......@@ -276,9 +270,6 @@ stages:
- source scripts/prepare_postgres_fdw.sh
- scripts/gitaly-test-spawn
- bundle exec rspec --color --format documentation --format RspecJunitFormatter --out junit_rspec.xml --tag geo ee/spec/
artifacts:
reports:
junit: junit_rspec.xml
.rspec-ee-pg-rails5: &rspec-ee-pg-rails5
<<: *rspec-ee-pg
......
......@@ -830,7 +830,7 @@ GEM
sexp_processor (~> 4.1)
rubyntlm (0.6.2)
rubypants (0.2.0)
rubyzip (1.2.1)
rubyzip (1.2.2)
rufus-scheduler (3.4.0)
et-orbi (~> 1.0)
rugged (0.27.4)
......
......@@ -838,7 +838,7 @@ GEM
sexp_processor (~> 4.1)
rubyntlm (0.6.2)
rubypants (0.2.0)
rubyzip (1.2.1)
rubyzip (1.2.2)
rufus-scheduler (3.4.0)
et-orbi (~> 1.0)
rugged (0.27.4)
......
......@@ -37,7 +37,7 @@
</script>
<template>
<div class="groups-list-tree-container">
<div class="groups-list-tree-container qa-groups-list-tree-container">
<div
v-if="searchEmpty"
class="has-no-search-results"
......
......@@ -66,6 +66,7 @@ class Projects::HooksController < Projects::ApplicationController
:enable_ssl_verification,
:token,
:url,
:push_events_branch_filter,
*ProjectHook.triggers.values
)
end
......
class TemplateFinder
prepend ::EE::TemplateFinder
VENDORED_TEMPLATES = {
dockerfiles: ::Gitlab::Template::DockerfileTemplate,
gitignores: ::Gitlab::Template::GitignoreTemplate,
gitlab_ci_ymls: ::Gitlab::Template::GitlabCiYmlTemplate
}.freeze
class << self
def build(type, params = {})
if type == :licenses
LicenseTemplateFinder.new(params)
else
new(type, params)
end
end
end
attr_reader :type, :params
attr_reader :vendored_templates
private :vendored_templates
def initialize(type, params = {})
@type = type
@params = params
@vendored_templates = VENDORED_TEMPLATES.fetch(type)
end
def execute
if params[:name]
vendored_templates.find(params[:name])
else
vendored_templates.all
end
end
end
......@@ -158,32 +158,35 @@ module BlobHelper
end
def licenses_for_select
return @licenses_for_select if defined?(@licenses_for_select)
grouped_licenses = LicenseTemplateFinder.new.execute.group_by(&:category)
categories = grouped_licenses.keys
@licenses_for_select = categories.each_with_object({}) do |category, hash|
hash[category] = grouped_licenses[category].map do |license|
{ name: license.name, id: license.id }
end
end
@licenses_for_select ||= template_dropdown_names(TemplateFinder.build(:licenses).execute)
end
def ref_project
@ref_project ||= @target_project || @project
end
def template_dropdown_names(items)
grouped = items.group_by(&:category)
categories = grouped.keys
categories.each_with_object({}) do |category, hash|
hash[category] = grouped[category].map do |item|
{ name: item.name, id: item.id }
end
end
end
private :template_dropdown_names
def gitignore_names
@gitignore_names ||= Gitlab::Template::GitignoreTemplate.dropdown_names
@gitignore_names ||= template_dropdown_names(TemplateFinder.build(:gitignores).execute)
end
def gitlab_ci_ymls
@gitlab_ci_ymls ||= Gitlab::Template::GitlabCiYmlTemplate.dropdown_names(params[:context])
@gitlab_ci_ymls ||= template_dropdown_names(TemplateFinder.build(:gitlab_ci_ymls).execute)
end
def dockerfile_names
@dockerfile_names ||= Gitlab::Template::DockerfileTemplate.dropdown_names
@dockerfile_names ||= template_dropdown_names(TemplateFinder.build(:dockerfiles).execute)
end
def blob_editor_paths
......
......@@ -110,10 +110,12 @@ module EventsHelper
event.note_target)
elsif event.note?
if event.note_target
event_note_target_path(event)
event_note_target_url(event)
end
elsif event.push?
push_event_feed_url(event)
elsif event.created_project?
project_url(event.project)
end
end
......@@ -145,14 +147,14 @@ module EventsHelper
end
end
def event_note_target_path(event)
def event_note_target_url(event)
if event.commit_note?
project_commit_path(event.project, event.note_target, anchor: dom_id(event.target))
project_commit_url(event.project, event.note_target, anchor: dom_id(event.target))
elsif event.project_snippet_note?
project_snippet_path(event.project, event.note_target, anchor: dom_id(event.target))
project_snippet_url(event.project, event.note_target, anchor: dom_id(event.target))
else
polymorphic_path([event.project.namespace.becomes(Namespace),
event.project, event.note_target],
polymorphic_url([event.project.namespace.becomes(Namespace),
event.project, event.note_target],
anchor: dom_id(event.target))
end
end
......@@ -166,7 +168,7 @@ module EventsHelper
event.note_target_reference
end
link_to(text, event_note_target_path(event), title: event.target_title, class: 'has-tooltip')
link_to(text, event_note_target_url(event), title: event.target_title, class: 'has-tooltip')
else
content_tag(:strong, '(deleted)')
end
......
module SortingHelper
prepend ::EE::SortingHelper
def sort_options_hash
{
sort_value_created_date => sort_title_created_date,
......
......@@ -51,6 +51,20 @@ module Ci
gzip: 3
}
# `file_location` indicates where actual files are stored.
# Ideally, actual files should be stored in the same directory, and use the same
# convention to generate its path. However, sometimes we can't do so due to backward-compatibility.
#
# legacy_path ... The actual file is stored at a path consists of a timestamp
# and raw project/model IDs. Those rows were migrated from
# `ci_builds.artifacts_file` and `ci_builds.artifacts_metadata`
# hashed_path ... The actual file is stored at a path consists of a SHA2 based on the project ID.
# This is the default value.
enum file_location: {
legacy_path: 1,
hashed_path: 2
}
FILE_FORMAT_ADAPTERS = {
gzip: Gitlab::Ci::Build::Artifacts::GzipFileAdapter
}.freeze
......@@ -75,6 +89,10 @@ module Ci
[nil, ::JobArtifactUploader::Store::LOCAL].include?(self.file_store)
end
def hashed_path?
super || self.try(:file_location).nil?
end
def expire_in
expire_at - Time.now if expire_at
end
......@@ -111,7 +129,7 @@ module Ci
end
def update_project_statistics_after_destroy
update_project_statistics(-self.size)
update_project_statistics(-self.size.to_i)
end
def update_project_statistics(difference)
......
......@@ -9,7 +9,7 @@ module Avatarable
include Gitlab::Utils::StrongMemoize
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }, if: :avatar_changed?
mount_uploader :avatar, AvatarUploader
......
......@@ -50,14 +50,20 @@ module ProtectedRef
.map(&:"#{action}_access_levels").flatten
end
# Returns all protected refs that match the given ref name.
# This checks all records from the scope built up so far, and does
# _not_ return a relation.
#
# This method optionally takes in a list of `protected_refs` to search
# through, to avoid calling out to the database.
def matching(ref_name, protected_refs: nil)
ProtectedRefMatcher.matching(self, ref_name, protected_refs: protected_refs)
(protected_refs || self.all).select { |protected_ref| protected_ref.matches?(ref_name) }
end
end
private
def ref_matcher
@ref_matcher ||= ProtectedRefMatcher.new(self)
@ref_matcher ||= RefMatcher.new(self.name)
end
end
......@@ -29,6 +29,12 @@ module TriggerableHooks
public_send(trigger) # rubocop:disable GitlabSecurity/PublicSend
end
def select_active(hooks_scope, data)
select do |hook|
ActiveHookFilter.new(hook).matches?(hooks_scope, data)
end
end
private
def triggerable_hooks(hooks)
......
class ActiveHookFilter
def initialize(hook)
@hook = hook
@push_events_filter_matcher = RefMatcher.new(@hook.push_events_branch_filter)
end
def matches?(hooks_scope, data)
return true if hooks_scope != :push_hooks
return true if @hook.push_events_branch_filter.blank?
branch_name = Gitlab::Git.branch_name(data[:ref])
@push_events_filter_matcher.matches?(branch_name)
end
end
......@@ -9,6 +9,7 @@ class WebHook < ActiveRecord::Base
allow_local_network: lambda(&:allow_local_requests?) }
validates :token, format: { without: /\n/ }
validates :push_events_branch_filter, branch_filter: true
def execute(data, hook_name)
WebHookService.new(self, data, hook_name).execute
......
......@@ -1201,10 +1201,9 @@ class Project < ActiveRecord::Base
def execute_hooks(data, hooks_scope = :push_hooks)
run_after_commit_or_now do
hooks.hooks_for(hooks_scope).each do |hook|
hooks.hooks_for(hooks_scope).select_active(hooks_scope, data).each do |hook|
hook.async_execute(data, hooks_scope.to_s)
end
SystemHooksService.new.execute_hooks(data, hooks_scope)
end
end
......
# frozen_string_literal: true
class ProtectedRefMatcher
def initialize(protected_ref)
@protected_ref = protected_ref
end
# Returns all protected refs that match the given ref name.
# This checks all records from the scope built up so far, and does
# _not_ return a relation.
#
# This method optionally takes in a list of `protected_refs` to search
# through, to avoid calling out to the database.
def self.matching(type, ref_name, protected_refs: nil)
(protected_refs || type.all).select { |protected_ref| protected_ref.matches?(ref_name) }
class RefMatcher
def initialize(ref_name_or_pattern)
@ref_name_or_pattern = ref_name_or_pattern
end
# Returns all branches/tags (among the given list of refs [`Gitlab::Git::Branch`])
# that match the current protected ref.
def matching(refs)
refs.select { |ref| @protected_ref.matches?(ref.name) }
refs.select { |ref| matches?(ref.name) }
end
# Checks if the protected ref matches the given ref name.
def matches?(ref_name)
return false if @protected_ref.name.blank?
return false if @ref_name_or_pattern.blank?
exact_match?(ref_name) || wildcard_match?(ref_name)
end
# Checks if this protected ref contains a wildcard
def wildcard?
@protected_ref.name && @protected_ref.name.include?('*')
@ref_name_or_pattern && @ref_name_or_pattern.include?('*')
end
protected
def exact_match?(ref_name)
@protected_ref.name == ref_name
@ref_name_or_pattern == ref_name
end
def wildcard_match?(ref_name)
......@@ -47,7 +37,7 @@ class ProtectedRefMatcher
def wildcard_regex
@wildcard_regex ||= begin
name = @protected_ref.name.gsub('*', 'STAR_DONT_ESCAPE')
name = @ref_name_or_pattern.gsub('*', 'STAR_DONT_ESCAPE')
quoted_name = Regexp.quote(name)
regex_string = quoted_name.gsub('STAR_DONT_ESCAPE', '.*?')
/\A#{regex_string}\z/
......
......@@ -5,6 +5,7 @@ class JobArtifactUploader < GitlabUploader
include ObjectStorage::Concern
ObjectNotReadyError = Class.new(StandardError)
UnknownFileLocationError = Class.new(StandardError)
storage_options Gitlab.config.artifacts
......@@ -23,10 +24,22 @@ class JobArtifactUploader < GitlabUploader
def dynamic_segment
raise ObjectNotReadyError, 'JobArtifact is not ready' unless model.id
creation_date = model.created_at.utc.strftime('%Y_%m_%d')
if model.hashed_path?
hashed_path
elsif model.legacy_path?
legacy_path
else
raise UnknownFileLocationError
end
end
def hashed_path
File.join(disk_hash[0..1], disk_hash[2..3], disk_hash,
creation_date, model.job_id.to_s, model.id.to_s)
model.created_at.utc.strftime('%Y_%m_%d'), model.job_id.to_s, model.id.to_s)
end
def legacy_path
File.join(model.created_at.utc.strftime('%Y_%m'), model.project_id.to_s, model.job_id.to_s)
end
def disk_hash
......
# BranchFilterValidator
#
# Custom validator for branch names. Squishes whitespace and ignores empty
# string. This only checks that a string is a valid git branch name. It does
# not check whether a branch already exists.
#
# Example:
#
# class Webhook < ActiveRecord::Base
# validates :push_events_branch_filter, branch_name: true
# end
#
class BranchFilterValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
value.squish! unless value.nil?
if value.present?
value_without_wildcards = value.tr('*', 'x')
unless Gitlab::GitRefValidator.validate(value_without_wildcards)
record.errors[attribute] << "is not a valid branch name"
end
unless value.length <= 4000
record.errors[attribute] << "is longer than the allowed length of 4000 characters."
end
end
end
private
def contains_wildcard?(value)
value.include?('*')
end
end
......@@ -336,7 +336,6 @@
.settings-content
= render partial: 'repository_mirrors_form'
-# EE-only
= render_if_exists 'admin/application_settings/geo', expanded: expanded
= render_if_exists 'admin/application_settings/external_authorization_service_form', expanded: expanded
......
%div{ xmlns: "http://www.w3.org/1999/xhtml" }
%p
%strong= event.author_name
= link_to "(#{truncate_sha(event.commit_id)})", project_commit_path(event.project, event.commit_id)
= link_to "(#{truncate_sha(event.commit_id)})", event_feed_url(event)
%i
at
= event.created_at.to_s(:short)
......
......@@ -25,7 +25,7 @@
.labels-container.prepend-top-5
- if @labels.any?
.other-labels
%h5 Labels
%h5= _('Labels')
%ul.content-list.manage-labels-list.js-other-labels
= render partial: 'shared/label', subject: @group, collection: @labels, as: :label, locals: { use_label_priority: false }
= paginate @labels, theme: 'gitlab'
......
......@@ -5,7 +5,7 @@
= render "layouts/init_auto_complete" if @gfm_form
= render 'peek/bar'
= header_message
= render "layouts/header/default"
= render partial: "layouts/header/default", locals: { project: @project, group: @group }
= render 'layouts/page', sidebar: sidebar, nav: nav
= footer_message
......
......@@ -4,7 +4,7 @@
%body{ class: "#{user_application_theme} #{@body_class} fullscreen-layout", data: { page: body_data_page } }
= render 'peek/bar'
= header_message
= render "layouts/header/default"
= render partial: "layouts/header/default", locals: { project: @project, group: @group }
= render 'shared/outdated_browser'
.mobile-overlay
.alert-wrapper
......
%header.navbar.navbar-gitlab.navbar-gitlab-new.qa-navbar.navbar-expand-sm
- if project
- search_path_url = search_path(project_id: project.id)
- elsif group
- search_path_url = search_path(group_id: group.id)
- else
- search_path_url = search_path
%header.navbar.navbar-gitlab.qa-navbar.navbar-expand-sm.navbar-gitlab-new
%a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content
.container-fluid
.header-content
......@@ -24,26 +31,25 @@
%li.nav-item.d-none.d-sm-none.d-md-block.m-auto
= render 'layouts/search' unless current_controller?(:search)
%li.nav-item.d-inline-block.d-sm-none.d-md-none
= link_to search_path, title: _('Search'), aria: { label: _("Search") }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= link_to search_path_url, title: _('Search'), aria: { label: _('Search') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon('search', size: 16)
- if header_link?(:issues)
= nav_link(path: 'dashboard#issues', html_options: { class: "user-counter" }) do
= link_to assigned_issues_dashboard_path, title: _('Issues'), class: 'dashboard-shortcuts-issues', aria: { label: _("Issues") }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= link_to assigned_issues_dashboard_path, title: _('Issues'), class: 'dashboard-shortcuts-issues', aria: { label: _('Issues') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon('issues', size: 16)
- issues_count = assigned_issuables_count(:issues)
%span.badge.badge-pill.issues-count{ class: ('hidden' if issues_count.zero?) }
= number_with_delimiter(issues_count)
- if header_link?(:merge_requests)
= nav_link(path: 'dashboard#merge_requests', html_options: { class: "user-counter" }) do
= link_to assigned_mrs_dashboard_path, title: _('Merge requests'), class: 'dashboard-shortcuts-merge_requests', aria: { label: _("Merge requests") }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= link_to assigned_mrs_dashboard_path, title: _('Merge requests'), class: 'dashboard-shortcuts-merge_requests', aria: { label: _('Merge requests') }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon('git-merge', size: 16)
- merge_requests_count = assigned_issuables_count(:merge_requests)
%span.badge.badge-pill.merge-requests-count{ class: ('hidden' if merge_requests_count.zero?) }
= number_with_delimiter(merge_requests_count)
- if header_link?(:todos)
= nav_link(controller: 'dashboard/todos', html_options: { class: "user-counter" }) do
= link_to dashboard_todos_path, title: _('Todos'), aria: { label: _("Todos") }, class: 'shortcuts-todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= link_to dashboard_todos_path, title: _('Todos'), aria: { label: _('Todos') }, class: 'shortcuts-todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon('todo-done', size: 16)
%span.badge.badge-pill.todos-count{ class: ('hidden' if todos_pending_count.zero?) }
= todos_count_format(todos_pending_count)
......@@ -56,7 +62,7 @@
= render 'layouts/header/current_user_dropdown'
- if header_link?(:admin_impersonation)
%li.nav-item.impersonation
= link_to admin_impersonation_path, class: 'nav-link impersonation-btn', method: :delete, title: _("Stop impersonation"), aria: { label: _('Stop impersonation') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
= link_to admin_impersonation_path, class: 'nav-link impersonation-btn', method: :delete, title: _('Stop impersonation'), aria: { label: _('Stop impersonation') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
= icon('user-secret')
- if header_link?(:sign_in)
%li.nav-item
......@@ -64,8 +70,7 @@
- sign_in_text = allow_signup? ? _('Sign in / Register') : _('Sign in')
= link_to sign_in_text, new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in'
%button.navbar-toggler.d-block.d-sm-none{ type: 'button' }
%span.sr-only= _("Toggle navigation")
%span.sr-only= _('Toggle navigation')
= sprite_icon('ellipsis_h', size: 12, css_class: 'more-icon js-navbar-toggle-right')
= sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left')
- expanded = Rails.env.test?
%section.settings.no-animate#default-branch-settings{ class: ('expanded' if expanded) }
.settings-header
%h4= _('Default Branch')
%button.btn.js-settings-toggle
= expanded ? _('Collapse') : _('Expand')
%p
= _('Select the branch you want to set as the default for this project. All merge requests and commits will automatically be made against this branch unless you specify a different one.')
.settings-content
- if @project.empty_repo?
.text-secondary
= _('A default branch cannot be chosen for an empty project.')
- else
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, anchor: 'default-branch-settings' }, authenticity_token: true do |f|
%fieldset
.form-group
= f.label :default_branch, "Default Branch", class: 'label-bold'
= f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'})
= f.submit 'Save changes', class: "btn btn-success"
......@@ -36,11 +36,6 @@
= render_if_exists 'projects/classification_policy_settings', f: f
- unless @project.empty_repo?
.form-group
= f.label :default_branch, "Default Branch", class: 'label-bold'
= f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'})
= render_if_exists 'shared/repository_size_limit_setting', form: f, type: :project
.form-group
......
- breadcrumb_title "Issues"
- add_to_breadcrumbs "Issues", project_issues_path(@project)
- breadcrumb_title "New"
- page_title "New Issue"
%h3.page-title
......
- breadcrumb_title "Merge Requests"
- add_to_breadcrumbs "Merge Requests", project_merge_requests_path(@project)
- breadcrumb_title "New"
- page_title "New Merge Request"
- if @merge_request.can_be_created && !params[:change_branches]
......
......@@ -2,6 +2,7 @@
- page_title _("Repository")
- @content_class = "limit-container-width" unless fluid_layout
= render "projects/default_branch/show"
= render "projects/push_rules/index"
= render "projects/mirrors/show"
......
.groups-empty-state
.groups-empty-state.qa-groups-empty-state
= custom_icon("icon_empty_groups")
.text-content
......
......@@ -17,6 +17,7 @@
%strong Push events
%p.light.ml-1
This URL will be triggered by a push to the repository
= form.text_field :push_events_branch_filter, class: 'form-control', placeholder: 'Branch name or wildcard pattern to trigger on (leave blank for all)'
%li
= form.check_box :tag_push_events, class: 'form-check-input'
= form.label :tag_push_events, class: 'list-label form-check-label ml-1' do
......
......@@ -18,7 +18,7 @@
= event_action_name(event)
%strong
- if event.note?
= link_to event.note_target.to_reference, event_note_target_path(event), class: 'has-tooltip', title: event.target_title
= link_to event.note_target.to_reference, event_note_target_url(event), class: 'has-tooltip', title: event.target_title
- elsif event.target
= link_to event.target.to_reference, [event.project.namespace.becomes(Namespace), event.project, event.target], class: 'has-tooltip', title: event.target_title
......
---
title: "Fix breadcrumb link to issues on new issue page"
merge_request: 21305
author: J.D. Bean
type: fixed
---
title: Move project settings for default branch under "Repository"
merge_request: 21380
author:
type: changed
---
title: Adds diverged_commits_count field to GET api/v4/projects/:project_id/merge_requests/:merge_request_iid
merge_request: 21405
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: Handle database statement timeouts in usage ping
merge_request: 21523
author:
type: fixed
---
title: "Fix breadcrumb link to merge requests on new merge request page"
merge_request: 21502
author: J.D. Bean
type: fixed
---
title: Fix links in RSS feed elements
merge_request: 21424
author: Marc Schwede
type: fixed
---
title: Update rubyzip to 1.2.2 (CVE-2018-1000544)
merge_request: 21460
author: Takuya Noguchi
type: security
---
title: Add background migrations for legacy artifacts
merge_request: 18615
author:
type: performance
---
title: Add gitaly_calls attribute to API logs
merge_request: 21496
author:
type: other
---
title: Add support for extendable CI/CD config with
merge_request: 21243
author:
type: added
---
title: Add branch filter to project webhooks
merge_request: 20338
author: Duana Saskia
type: added
---
title: Limit navbar search for current project or group for small viewports
merge_request: 18634
author: George Tsiolis
type: changed
---
title: 'Rails 5: fix hashed_path? method that looks up file_location that doesn''t
exist when running certain migration specs'
merge_request: 21510
author: Jasper Maes
type: other
---
title: 'Rails 5: include opclasses in rails 5 schema dump'
merge_request: 21416
author: Jasper Maes
type: fixed
---
title: Disable project avatar validation if avatar has not changed
merge_request:
author:
type: performance
---
title: Ignore irrelevant sql commands in metrics
merge_request: 21498
author:
type: other
......@@ -235,8 +235,9 @@
:why: https://github.com/component/inherit/blob/master/LICENSE
:versions: []
:when: 2017-01-14 20:10:41.804804000 Z
- - :approve
- - :license
- fsevents
- MIT
- :who: Matt Lee
:why: https://github.com/strongloop/fsevents/blob/master/LICENSE
:versions: []
......@@ -380,8 +381,9 @@
:why: https://github.com/Tjatse/ansi-html/blob/master/LICENSE
:versions: []
:when: 2017-04-10 05:42:12.898178000 Z
- - :approve
- - :license
- map-stream
- MIT
- :who: Mike Greiling
:why: https://github.com/dominictarr/map-stream/blob/master/LICENCE
:versions: []
......@@ -458,8 +460,9 @@
:why: CC0 1.0 - https://github.com/jonathantneal/svg4everybody/blob/master/LICENSE.md
:versions: []
:when: 2017-09-13 17:31:16.425819400 Z
- - :approve
- - :license
- "@gitlab-org/gitlab-svgs"
- MIT
- :who: Tim Zallmann
:why: Our own library - GitLab License https://gitlab.com/gitlab-org/gitlab-svgs
:versions: []
......@@ -528,8 +531,9 @@
:why: https://github.com/mafintosh/cyclist/blob/master/LICENSE
:versions: []
:when: 2018-02-20 21:37:43.774978000 Z
- - :approve
- - :license
- bitsyntax
- MIT
- :who: Mike Greiling
:why: https://github.com/squaremo/bitsyntax-js/blob/master/LICENSE-MIT
:versions: []
......@@ -540,8 +544,9 @@
:why: https://github.com/xtuc/webassemblyjs/blob/master/LICENSE
:versions: []
:when: 2018-06-08 05:30:56.764116000 Z
- - :approve
- - :license
- "@gitlab-org/gitlab-ui"
- MIT
- :who: Clement Ho
:why: Our own library
:versions: []
......@@ -552,20 +557,23 @@
:why: https://github.com/pieroxy/lz-string/blob/master/LICENSE.txt
:versions: []
:when: 2018-08-03 08:22:44.973457000 Z
- - :approve
- - :license
- smooshpack
- LGPL
- :who: Phil Hughes
:why: https://github.com/CompuIves/codesandbox-client/blob/master/packages/sandpack/LICENSE.md
:versions: []
:when: 2018-08-03 08:24:29.578991000 Z
- - :approve
- - :license
- codesandbox-import-util-types
- LGPL
- :who: Phil Hughes
:why: https://github.com/codesandbox-app/codesandbox-importers/blob/master/packages/types/LICENSE
:versions: []
:when: 2018-08-03 12:22:47.574421000 Z
- - :approve
- - :license
- codesandbox-import-utils
- LGPL
- :who: Phil Hughes
:why: https://github.com/codesandbox-app/codesandbox-importers/blob/master/packages/import-utils/LICENSE
:versions: []
......@@ -573,7 +581,7 @@
- - :ignore_group
- devDependencies
- :who: Winnie Hellmann
:why: NPM packages used for development are not distributed with the final product and are therefore
exempt.
:why: NPM packages used for development are not distributed with the final product
and are therefore exempt.
:versions: []
:when: 2018-08-30 12:06:35.668181000 Z
......@@ -7,11 +7,12 @@
# the old Rails 4 schema layout is still used
module MysqlSetLengthForBinaryIndex
def add_index(table_name, column_names, options = {})
options[:length] ||= {}
Array(column_names).each do |column_name|
column = ActiveRecord::Base.connection.columns(table_name).find { |c| c.name == column_name }
if column&.type == :binary
options[:length] = 20
options[:length][column_name] = 20
end
end
......@@ -27,11 +28,12 @@ if Gitlab.rails5?
module MysqlSetLengthForBinaryIndexAndIgnorePostgresOptionsForSchema
# This method is used in Rails 5 schema loading as t.index
def index(column_names, options = {})
options[:length] ||= {}
Array(column_names).each do |column_name|
column = columns.find { |c| c.name == column_name }
if column&.type == :binary
options[:length] = 20
options[:length][column_name] = 20
end
end
......
......@@ -144,7 +144,10 @@ module ActiveRecord
[column, opclass] if opclass
end.compact]
IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where, nil, using, opclasses)
index_attrs = [table_name, index_name, unique, column_names, [], orders, where, nil, using, opclasses]
index_attrs.insert(-2, nil) if Gitlab.rails5? # include index comment for Rails 5
IndexDefinition.new(*index_attrs)
end
end.compact
end
......@@ -172,29 +175,38 @@ module ActiveRecord
def indexes(table, stream)
if (indexes = @connection.indexes(table)).any?
add_index_statements = indexes.map do |index|
statement_parts = [
"add_index #{remove_prefix_and_suffix(index.table).inspect}",
index.columns.inspect,
"name: #{index.name.inspect}",
]
statement_parts << 'unique: true' if index.unique
index_lengths = (index.lengths || []).compact
statement_parts << "length: #{Hash[index.columns.zip(index.lengths)].inspect}" if index_lengths.any?
index_orders = index.orders || {}
statement_parts << "order: #{index.orders.inspect}" if index_orders.any?
statement_parts << "where: #{index.where.inspect}" if index.where
statement_parts << "using: #{index.using.inspect}" if index.using
statement_parts << "type: #{index.type.inspect}" if index.type
statement_parts << "opclasses: #{index.opclasses}" if index.opclasses.present?
" #{statement_parts.join(', ')}"
table_name = remove_prefix_and_suffix(index.table).inspect
" add_index #{([table_name]+index_parts(index)).join(', ')}"
end
stream.puts add_index_statements.sort.join("\n")
stream.puts
end
end
def indexes_in_create(table, stream)
if (indexes = @connection.indexes(table)).any?
index_statements = indexes.map do |index|
" t.index #{index_parts(index).join(', ')}"
end
stream.puts index_statements.sort.join("\n")
end
end
def index_parts(index)
index_parts = [
index.columns.inspect,
"name: #{index.name.inspect}",
]
index_parts << "unique: true" if index.unique
index_parts << "length: { #{format_options(index.lengths)} }" if index.lengths.present?
index_parts << "order: { #{format_options(index.orders)} }" if index.orders.present?
index_parts << "where: #{index.where.inspect}" if index.where
index_parts << "using: #{index.using.inspect}" if index.using
index_parts << "type: #{index.type.inspect}" if index.type
index_parts << "opclasses: #{index.opclasses.inspect}" if index.opclasses.present?
index_parts << "comment: #{index.comment.inspect}" if Gitlab.rails5? && index.comment
index_parts
end
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddPushEventsBranchFilterToWebHooks < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :web_hooks, :push_events_branch_filter, :text
end
end
class AddFileLocationToCiJobArtifacts < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :ci_job_artifacts, :file_location, :integer, limit: 2
end
end
class AddPartialIndexToCiBuildsArtifactsFile < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'partial_index_ci_builds_on_id_with_legacy_artifacts'.freeze
disable_ddl_transaction!
def up
add_concurrent_index(:ci_builds, :id, where: "artifacts_file <> ''", name: INDEX_NAME)
end
def down
remove_concurrent_index_by_name(:ci_builds, INDEX_NAME)
end
end
class MigrateLegacyArtifactsToJobArtifacts < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'MigrateLegacyArtifacts'.freeze
BATCH_SIZE = 100
disable_ddl_transaction!
class Build < ActiveRecord::Base
include EachBatch
self.table_name = 'ci_builds'
self.inheritance_column = :_type_disabled
scope :with_legacy_artifacts, -> { where("artifacts_file <> ''") }
end
def up
MigrateLegacyArtifactsToJobArtifacts::Build
.with_legacy_artifacts.tap do |relation|
queue_background_migration_jobs_by_range_at_intervals(relation,
MIGRATION,
5.minutes,
batch_size: BATCH_SIZE)
end
end
def down
# no-op
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180826111825) do
ActiveRecord::Schema.define(version: 20180831152625) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -437,6 +437,7 @@ ActiveRecord::Schema.define(version: 20180826111825) do
add_index "ci_builds", ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree
add_index "ci_builds", ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree
add_index "ci_builds", ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree
add_index "ci_builds", ["id"], name: "partial_index_ci_builds_on_id_with_legacy_artifacts", where: "(artifacts_file <> ''::text)", using: :btree
add_index "ci_builds", ["name"], name: "index_ci_builds_on_name_for_security_products_values", where: "((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('sast'::character varying)::text]))", using: :btree
add_index "ci_builds", ["project_id", "id"], name: "index_ci_builds_on_project_id_and_id", using: :btree
add_index "ci_builds", ["protected"], name: "index_ci_builds_on_protected", using: :btree
......@@ -493,6 +494,7 @@ ActiveRecord::Schema.define(version: 20180826111825) do
t.integer "file_store"
t.binary "file_sha256"
t.integer "file_format", limit: 2
t.integer "file_location", limit: 2
end
add_index "ci_job_artifacts", ["expire_at", "job_id"], name: "index_ci_job_artifacts_on_expire_at_and_job_id", using: :btree
......@@ -2231,6 +2233,7 @@ ActiveRecord::Schema.define(version: 20180826111825) do
t.boolean "pages_https_only", default: true
t.string "external_webhook_token"
t.boolean "packages_enabled"
t.boolean "merge_requests_author_approval"
end
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
......@@ -2962,6 +2965,7 @@ ActiveRecord::Schema.define(version: 20180826111825) do
t.boolean "repository_update_events", default: false, null: false
t.boolean "job_events", default: false, null: false
t.boolean "confidential_note_events"
t.text "push_events_branch_filter"
end
add_index "web_hooks", ["project_id"], name: "index_web_hooks_on_project_id", using: :btree
......
......@@ -352,7 +352,7 @@ Example requests:
- Using the `job_token` parameter (only inside `.gitlab-ci.yml`):
```
curl --location --header --form "job-token=$CI_JOB_TOKEN" "https://gitlab.example.com/api/v4/projects/1/jobs/8/artifacts"
curl --location --form "job-token=$CI_JOB_TOKEN" "https://gitlab.example.com/api/v4/projects/1/jobs/8/artifacts"
```
Response:
......
......@@ -353,6 +353,7 @@ Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `merge_request_iid` (required) - The internal ID of the merge request
- `render_html` (optional) - If `true` response includes rendered HTML for title and description
- `include_diverged_commits_count` (optional) - If `true` response includes the commits behind the target branch
```json
{
......@@ -437,7 +438,8 @@ Parameters:
"username" : "root",
"id" : 1,
"name" : "Administrator"
}
},
"diverged_commits_count": 2
}
```
......
......@@ -1367,6 +1367,7 @@ GET /projects/:id/hooks/:hook_id
"url": "http://example.com/hook",
"project_id": 3,
"push_events": true,
"push_events_branch_filter": "",
"issues_events": true,
"confidential_issues_events": true,
"merge_requests_events": true,
......@@ -1393,6 +1394,7 @@ POST /projects/:id/hooks
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `url` | string | yes | The hook URL |
| `push_events` | boolean | no | Trigger hook on push events |
| `push_events_branch_filter` | string | no | Trigger hook on push events for matching branches only |
| `issues_events` | boolean | no | Trigger hook on issues events |
| `confidential_issues_events` | boolean | no | Trigger hook on confidential issues events |
| `merge_requests_events` | boolean | no | Trigger hook on merge requests events |
......@@ -1418,6 +1420,7 @@ PUT /projects/:id/hooks/:hook_id
| `hook_id` | integer | yes | The ID of the project hook |
| `url` | string | yes | The hook URL |
| `push_events` | boolean | no | Trigger hook on push events |
| `push_events_branch_filter` | string | no | Trigger hook on push events for matching branches only |
| `issues_events` | boolean | no | Trigger hook on issues events |
| `confidential_issues_events` | boolean | no | Trigger hook on confidential issues events |
| `merge_requests_events` | boolean | no | Trigger hook on merge requests events |
......
<
......@@ -56,6 +56,7 @@ A job is defined by a list of parameters that define the job behavior.
| Keyword | Required | Description |
|---------------|----------|-------------|
| script | yes | Defines a shell script which is executed by Runner |
| extends | no | Defines a configuration entry that this job is going to inherit from |
| image | no | Use docker image, covered in [Using Docker Images](../docker/using_docker_images.md#define-image-and-services-from-gitlab-ciyml) |
| services | no | Use docker services, covered in [Using Docker Images](../docker/using_docker_images.md#define-image-and-services-from-gitlab-ciyml) |
| stage | no | Defines a job stage (default: `test`) |
......@@ -75,6 +76,81 @@ A job is defined by a list of parameters that define the job behavior.
| coverage | no | Define code coverage settings for a given job |
| retry | no | Define how many times a job can be auto-retried in case of a failure |
### `extends`
> Introduced in GitLab 11.3
`extends` defines an entry name that a job, that uses `extends` is going to
inherit from.
`extends` in an alternative to using [YAML anchors](#anchors) that is a little
more flexible and readable.
```yaml
.tests:
only:
refs:
- branches
rspec:
extends: .tests
script: rake rspec
stage: test
only:
variables:
- $RSPEC
```
In the example above the `rspec` job is going to inherit from `.tests`
template. GitLab will perform a reverse deep merge, what means that it will
merge `rspec` contents into `.tests` recursively, and it is going to result in
following configuration of the `rspec` job:
```yaml
rspec:
script: rake rspec
stage: test
only:
refs:
- branches
variables:
- $RSPEC
```
`.tests` in this example is a [hidden key](#hidden-keys-jobs), but it is
possible to inherit from regular jobs as well.
`extends` supports multi-level inheritance, however it is not recommended to
use more than three levels of inheritance. Maximum nesting level supported is
10 levels.
```yaml