Commit fd40843a authored by Robert Speicher's avatar Robert Speicher

Merge branch 'ce-to-ee-2018-09-05' into 'master'

CE upstream - 2018-09-05 15:23 UTC

See merge request gitlab-org/gitlab-ee!7252
parents e952f958 cb677592
......@@ -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
......
......@@ -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,13 +147,13 @@ 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),
polymorphic_url([event.project.namespace.becomes(Namespace),
event.project, event.note_target],
anchor: dom_id(event.target))
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
......
......@@ -90,7 +90,7 @@ module Ci
end
def hashed_path?
super || self.file_location.nil?
super || self.try(:file_location).nil?
end
def expire_in
......
......@@ -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/
......
# 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
%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)
......
......@@ -5,7 +5,7 @@
- else
- search_path_url = search_path
%header.navbar.navbar-gitlab.navbar-gitlab-new.qa-navbar.navbar-expand-sm
%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
......
......@@ -3,7 +3,10 @@
- @content_class = "limit-container-width" unless fluid_layout
= render "projects/default_branch/show"
<<<<<<< HEAD
= render "projects/push_rules/index"
=======
>>>>>>> upstream/master
= render "projects/mirrors/show"
-# Protected branches & tags use a lot of nested partials.
......
.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: 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: Fix links in RSS feed elements
merge_request: 21424
author: Marc Schwede
type: fixed
---
title: Add branch filter to project webhooks
merge_request: 20338
author: Duana Saskia
type: added
---
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: 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
......
# 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
......@@ -2965,6 +2965,7 @@ ActiveRecord::Schema.define(version: 20180831152625) 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
......
......@@ -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 |
......
......@@ -95,6 +95,8 @@ Gitlab::Git::DiffCollection.collection_limits[:max_bytes] = Gitlab::Git::DiffCol
No more files will be rendered at all if 5 megabytes have already been rendered.
*Note:* All collection limit parameters are currently sent and applied on Gitaly. That is, once the limit is surpassed,
Gitaly will only return the safe amount of data to be persisted on `merge_request_diff_files`.
### Individual diff file limits
......@@ -106,12 +108,17 @@ Gitlab::Git::Diff::COLLAPSE_LIMIT = 10.kilobytes
File diff will be collapsed (but be expandable) if it is larger than 10 kilobytes.
*Note:* Although this nomenclature (Collapsing) is also used on Gitaly, this limit is only used on GitLab (hardcoded - not sent to Gitaly).
Gitaly will only return `Diff.Collapsed` (RPC) when surpassing collection limits.
```ruby
Gitlab::Git::Diff::SIZE_LIMIT = 100.kilobytes
```
File diff will not be rendered if it's larger than 100 kilobytes.
*Note:* This limit is currently hardcoded and applied on Gitaly and the RPC returns `Diff.TooLarge` when this limit is surpassed.
Although we're still also applying it on GitLab, we should remove the redundancy from GitLab once we're confident with the Gitaly integration.
```ruby
Commit::DIFF_SAFE_LINES = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines] = 5000
......@@ -119,6 +126,8 @@ Commit::DIFF_SAFE_LINES = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines
File diff will be suppressed (technically different from collapsed, but behaves the same, and is expandable) if it has more than 5000 lines.
*Note:* This limit is currently hardcoded and only applied on GitLab.
## Viewers
Diff Viewers, which can be found on `models/diff_viewer/*` are classes used to map metadata about each type of Diff File. It has information
......
......@@ -105,6 +105,7 @@ module API
expose :project_id, :issues_events, :confidential_issues_events
expose :note_events, :confidential_note_events, :pipeline_events, :wiki_page_events
expose :job_events
expose :push_events_branch_filter
end
class SharedGroup < Grape::Entity
......@@ -689,6 +690,8 @@ module API
expose :diff_refs, using: Entities::DiffRefs
expose :diverged_commits_count, as: :diverged_commits_count, if: -> (_, options) { options[:include_diverged_commits_count] }
def build_available?(options)
options[:project]&.feature_available?(:builds, options[:current_user])
end
......
......@@ -235,6 +235,7 @@ module API
params do
requires :merge_request_iid, type: Integer, desc: 'The IID of a merge request'
optional :render_html, type: Boolean, desc: 'Returns the description and title rendered HTML'
optional :include_diverged_commits_count, type: Boolean, desc: 'Returns the commits count behind the target branch'
end
desc 'Get a single merge request' do
success Entities::MergeRequest
......@@ -242,7 +243,7 @@ module API
get ':id/merge_requests/:merge_request_iid' do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project, render_html: params[:render_html]
present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project, render_html: params[:render_html], include_diverged_commits_count: params[:include_diverged_commits_count]
end
desc 'Get the participants of a merge request' do
......
......@@ -20,6 +20,7 @@ module API
optional :wiki_page_events, type: Boolean, desc: "Trigger hook on wiki events"
optional :enable_ssl_verification, type: Boolean, desc: "Do SSL verification when triggering the hook"
optional :token, type: String, desc: "Secret token to validate received payloads; this will not be returned in the response"
optional :push_events_branch_filter, type: String, desc: "Trigger hook on specified branch only"
end
end
......@@ -63,6 +64,7 @@ module API
present hook, with: Entities::ProjectHook
else
error!("Invalid url given", 422) if hook.errors[:url].present?
error!("Invalid branch filter given", 422) if hook.errors[:push_events_branch_filter].present?
not_found!("Project hook #{hook.errors.messages}")
end
......@@ -84,6 +86,7 @@ module API
present hook, with: Entities::ProjectHook
else
error!("Invalid url given", 422) if hook.errors[:url].present?
error!("Invalid branch filter given", 422) if hook.errors[:push_events_branch_filter].present?
not_found!("Project hook #{hook.errors.messages}")
end
......
......@@ -6,9 +6,15 @@ module Gitlab
include Gitlab::Metrics::Methods
attach_to :active_record
IGNORABLE_SQL = %w{BEGIN COMMIT}.freeze
def sql(event)
return unless current_transaction
payload = event.payload
return if payload[:name] == 'SCHEMA' || IGNORABLE_SQL.include?(payload[:sql])
self.class.gitlab_sql_duration_seconds.observe(current_transaction.labels, event.duration / 1000.0)
current_transaction.increment(:sql_duration, event.duration, false)
......
......@@ -250,6 +250,7 @@ module QA
module Component
autoload :ClonePanel, 'qa/page/component/clone_panel'
autoload :Dropzone, 'qa/page/component/dropzone'
autoload :GroupsFilter, 'qa/page/component/groups_filter'
autoload :Select2, 'qa/page/component/select2'
end
end
......
......@@ -2,7 +2,7 @@ module QA
module Factory
module Resource
class Group < Factory::Base
attr_writer :path, :description
attr_accessor :path, :description
dependency Factory::Resource::Sandbox, as: :sandbox
......@@ -14,17 +14,23 @@ module QA
def fabricate!
sandbox.visit!
Page::Group::Show.perform do |page|
if page.has_subgroup?(@path)
page.go_to_subgroup(@path)
Page::Group::Show.perform do |group_show|
if group_show.has_subgroup?(path)
group_show.go_to_subgroup(path)
else
page.go_to_new_subgroup
group_show.go_to_new_subgroup
Page::Group::New.perform do |group|
group.set_path(@path)
group.set_description(@description)
group.set_visibility('Public')
group.create
Page::Group::New.perform do |group_new|
group_new.set_path(path)
group_new.set_description(description)
group_new.set_visibility('Public')
group_new.create
end
# Ensure that the group was actually created
group_show.wait(time: 1) do
group_show.has_text?(path) &&
group_show.has_new_project_or_subgroup_dropdown?
end
end
end
......
# frozen_string_literal: true
module QA
module Page
module Component
module GroupsFilter
def self.included(base)
base.view 'app/views/shared/groups/_search_form.html.haml' do
element :groups_filter, 'search_field_tag :filter'
element :groups_filter_placeholder, 'Filter by name...'
end
base.view 'app/views/shared/groups/_empty_state.html.haml' do
element :groups_empty_state
end
base.view 'app/assets/javascripts/groups/components/groups.vue' do
element :groups_list_tree_container
end
end
private
def filter_by_name(name)
wait(reload: false) do
page.has_css?(element_selector_css(:groups_empty_state)) ||
page.has_css?(element_selector_css(:groups_list_tree_container))
end
fill_in 'Filter by name...', with: name
end
end
end
end
end
......@@ -2,19 +2,12 @@ module QA
module Page
module Dashboard
class Groups < Page::Base
view 'app/views/shared/groups/_search_form.html.haml' do
element :groups_filter, 'search_field_tag :filter'
element :groups_filter_placeholder, 'Filter by name...'
end
include Page::Component::GroupsFilter
view 'app/views/dashboard/_groups_head.html.haml' do
element :new_group_button, 'link_to _("New group")'
end
def filter_by_name(name)
fill_in 'Filter by name...', with: name
end
def has_group?(name)
filter_by_name(name)
......
......@@ -5,6 +5,7 @@ module QA
prepend QA::EE::Page::Dashboard::Projects
view 'app/views/dashboard/projects/index.html.haml'
view 'app/views/shared/projects/_search_form.html.haml' do
element :form_filter_by_name, /form_tag.+id: 'project-filter-form'/
end
......@@ -15,6 +16,8 @@ module QA
find_link(text: name).click
end
private
def filter_by_name(name)
page.within('form#project-filter-form') do
fill_in :name, with: name
......
......@@ -2,6 +2,8 @@ module QA
module Page
module Group
class Show < Page::Base
include Page::Component::GroupsFilter
view 'app/views/groups/show.html.haml' do
element :new_project_or_subgroup_dropdown, '.new-project-subgroup'
element :new_project_or_subgroup_dropdown_toggle, '.dropdown-toggle'
......@@ -21,8 +23,8 @@ module QA
click_link name
end
def filter_by_name(name)
fill_in 'Filter by name...', with: name
def has_new_project_or_subgroup_dropdown?
page.has_css?(element_selector_css(:new_project_or_subgroup_dropdown))
end
def has_subgroup?(name)
......
......@@ -28,12 +28,8 @@ module QA
Specs::Runner.perform do |specs|
specs.tty = true
specs.options =
if rspec_options.any?
rspec_options
else
['--tag', self.class.focus.join(','), '--', ::File.expand_path('../specs/features', __dir__)]
end
specs.tags = self.class.focus
specs.options = rspec_options if rspec_options.any?
end
end
end
......
......@@ -27,12 +27,7 @@ module QA
Specs::Runner.perform do |specs|
specs.tty = true
specs.options =
if rspec_options.any?
rspec_options
else
['--', ::File.expand_path('../../specs/features', __dir__)]
end
specs.options = rspec_options if rspec_options.any?
end
end
end
......
......@@ -30,7 +30,7 @@ module QA
push.project = project
push.directory = Pathname
.new(__dir__)
.join('../../../fixtures/auto_devops_rack')
.join('../../../../../fixtures/auto_devops_rack')
push.commit_message = 'Create Auto DevOps compatible rack application'
end
......
......@@ -16,9 +16,9 @@ module QA
args.push('--tty') if tty
if tags.any?
tags.each { |tag| args.push(['-t', tag.to_s]) }
tags.each { |tag| args.push(['--tag', tag.to_s]) }
else
args.push(%w[-t ~orchestrated])
args.push(%w[--tag ~orchestrated])
end
args.push(options)
......
......@@ -29,7 +29,7 @@ describe QA::Git::Repository do
def cd_empty_temp_directory
tmp_dir = 'tmp/git-repository-spec/'
FileUtils.rm_r(tmp_dir) if ::File.exist?(tmp_dir)
FileUtils.rm_rf(tmp_dir) if ::File.exist?(tmp_dir)
FileUtils.mkdir_p tmp_dir
FileUtils.cd tmp_dir
end
......
describe QA::Scenario::Test::Instance::All do
subject do
Class.new(described_class) do
tags :rspec, :foo
end
end
context '#perform' do
let(:arguments) { spy('Runtime::Scenario') }
let(:release) { spy('Runtime::Release') }
let(:runner) { spy('Specs::Runner') }
before do
stub_const('QA::Runtime::Release', release)
stub_const('QA::Runtime::Scenario', arguments)
stub_const('QA::Specs::Runner', runner)
allow(runner).to receive(:perform).and_yield(runner)
end
it 'sets an address of the subject' do
subject.perform("hello")
expect(arguments).to have_received(:define)
.with(:gitlab_address, "hello")
end
context 'no paths' do
it 'calls runner with default arguments' do
subject.perform("test")
expect(runner).to have_received(:options=)
.with(['--tag', 'rspec,foo', '--', ::File.expand_path('../../../../qa/specs/features', __dir__)])
end
end
context 'specifying paths' do
it 'calls runner with paths' do
subject.perform('test', 'path1', 'path2')
expect(runner).to have_received(:options=).with(%w[path1 path2])
end
end
end
it_behaves_like 'a QA scenario class'
end
describe QA::Scenario::Test::Instance::Smoke do
subject { Class.new(described_class) { tags :smoke } }
context '#perform' do
let(:arguments) { spy('Runtime::Scenario') }
let(:release) { spy('Runtime::Release') }
let(:runner) { spy('Specs::Runner') }
before do
stub_const('QA::Runtime::Release', release)
stub_const('QA::Runtime::Scenario', arguments)
stub_const('QA::Specs::Runner', runner)
allow(runner).to receive(:perform).and_yield(runner)
end
it 'sets an address of the subject' do
subject.perform("hello")
expect(arguments).to have_received(:define)
.with(:gitlab_address, "hello")
end
it 'has a smoke tag' do
expect(subject.focus).to eq([:smoke]) # rubocop:disable Focus
end
context 'no paths' do
it 'calls runner with default arguments' do
subject.perform("test")
expect(runner).to have_received(:options=)
.with(['--tag', 'smoke', '--', ::File.expand_path('../../../../qa/specs/features', __dir__)])
end
end
context 'specifying paths' do
it 'calls runner with paths' do
subject.perform('test', 'path1', 'path2')
expect(runner).to have_received(:options=).with(%w[path1 path2])
end
end
it_behaves_like 'a QA scenario class' do
let(:tags) { [:smoke] }
end
end
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::Github do
context '#perform' do
let(:env) { spy('Runtime::Env') }
before do
stub_const('QA::Runtime::Env', env)
end
it_behaves_like 'a QA scenario class' do
let(:tags) { [:github] }
it 'requires a GitHub access token' do
subject.perform('gitlab_address')
expect(env).to have_received(:require_github_access_token!)
end
end
end
end
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::Kubernetes do
context '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:kubernetes] }
end
end
end
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::LDAP do
context '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:ldap] }
end
end
end
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::Mattermost do
context '#perform' do
it_behaves_like 'a QA scenario class' do
let(:args) { %w[gitlab_address mattermost_address] }
let(:tags) { [:mattermost] }
let(:options) { ['path1']}
it 'requires a GitHub access token' do
subject.perform(*args)
expect(attributes).to have_received(:define)
.with(:mattermost_address, 'mattermost_address')
end
end
end
end
# frozen_string_literal: true
describe QA::Scenario::Test::Integration::ObjectStorage do
context '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:object_storage] }
end
end
end
# frozen_string_literal: true
describe QA::Specs::Runner do
context '#perform' do
before do
allow(QA::Runtime::Browser).to receive(:configure!)
end
it 'excludes the orchestrated tag by default' do
expect(RSpec::Core::Runner).to receive(:run)
.with(['--tag', '~orchestrated', File.expand_path('../../qa/specs/features', __dir__)], $stderr, $stdout)
.and_return(0)
subject.perform
end
context 'when tty is set' do
subject do
described_class.new.tap do |runner|
runner.tty = true
end
end
it 'sets the `--tty` flag' do
expect(RSpec::Core::Runner).to receive(:run)
.with(['--tty', '--tag', '~orchestrated', File.expand_path('../../qa/specs/features', __dir__)], $stderr, $stdout)
.and_return(0)
subject.perform
end
end
context 'when tags are set' do
subject do
described_class.new.tap do |runner|
runner.tags = %i[orchestrated github]
end
end
it 'focuses on the given tags' do
expect(RSpec::Core::Runner).to receive(:run)
.with(['--tag', 'orchestrated', '--tag', 'github', File.expand_path('../../qa/specs/features', __dir__)], $stderr, $stdout)
.and_return(0)
subject.perform
end
end
end
end
# frozen_string_literal: true
shared_examples 'a QA scenario class' do
let(:attributes) { spy('Runtime::Scenario') }
let(:release) { spy('Runtime::Release') }
let(:runner) { spy('Specs::Runner') }
let(:args) { ['gitlab_address'] }
let(:tags) { [] }
let(:options) { %w[path1 path2] }
before do
stub_const('QA::Runtime::Release', release)
stub_const('QA::Runtime::Scenario', attributes)
stub_const('QA::Specs::Runner', runner)
allow(runner).to receive(:perform).and_yield(runner)
end
it 'responds to perform' do
expect(subject).to respond_to(:perform)
end
it 'sets an address of the subject' do
subject.perform(*args)
expect(attributes).to have_received(:define).with(:gitlab_address, 'gitlab_address')
end
it 'performs before hooks' do
subject.perform(*args)
expect(release).to have_received(:perform_before_hooks)
end
it 'sets tags on runner' do
subject.perform(*args)
expect(runner).to have_received(:tags=).with(tags)
end
context 'specifying RSpec options' do
it 'sets options on runner' do
subject.perform(*args, *options)
expect(runner).to have_received(:options=).with(options)
end
end
end
......@@ -51,6 +51,7 @@ describe 'Projects > Settings > Integration settings' do
fill_in 'hook_url', with: url
check 'Tag push events'
fill_in 'hook_push_events_branch_filter', with: 'master'
check 'Enable SSL verification'
check 'Job events'
......
......@@ -25,4 +25,47 @@ describe EventsHelper do
expect(helper.event_commit_title("foo & bar")).to eq("foo & bar")
end
end
describe '#event_feed_url' do
let(:event) { create(:event) }
let(:project) { create(:project, :public, :repository) }
it "returns project issue url" do
event.target = create(:issue)
expect(helper.event_feed_url(event)).to eq(project_issue_url(event.project, event.issue))
end
it "returns project merge_request url" do
event.target = create(:merge_request)
expect(helper.event_feed_url(event)).to eq(project_merge_request_url(event.project, event.merge_request))
end
it "returns project commit url" do
event.target = create(:note_on_commit, project: project)
expect(helper.event_feed_url(event)).to eq(project_commit_url(event.project, event.note_target))
end
it "returns event note target url" do
event.target = create(:note)
expect(helper.event_feed_url(event)).to eq(event_note_target_url(event))
end
it "returns project url" do
event.project = project
event.action = 1
expect(helper.event_feed_url(event)).to eq(project_url(event.project))
end
it "returns push event feed url" do
event = create(:push_event)
create(:push_event_payload, event: event, action: :pushed)
expect(helper.event_feed_url(event)).to eq(push_event_feed_url(event))
end
end
end
......@@ -419,6 +419,7 @@ ProjectHook:
- type
- service_id
- push_events
- push_events_branch_filter
- issues_events
- merge_requests_events
- tag_push_events
......
......@@ -42,6 +42,65 @@ describe Gitlab::Metrics::Subscribers::ActiveRecord do
subscriber.sql(event)
end
context 'events are internal to Rails or irrelevant' do
let(:schema_event) do
double(
:event,
name: 'sql.active_record',
payload: {
sql: "SELECT attr.attname FROM pg_attribute attr INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = any(cons.conkey) WHERE cons.contype = 'p' AND cons.conrelid = '\"projects\"'::regclass",
name: 'SCHEMA',
connection_id: 135,
statement_name: nil,
binds: []
},
duration: 0.7
)
end
let(:begin_event) do
double(
:event,
name: 'sql.active_record',
payload: {
sql: "BEGIN",
name: nil,
connection_id: 231,
statement_name: nil,
binds: []
},
duration: 1.1
)
end
let(:commit_event) do
double(
:event,
name: 'sql.active_record',
payload: {
sql: "COMMIT",
name: nil,
connection_id: 212,
statement_name: nil,
binds: []
},
duration: 1.6
)
end
it 'skips schema/begin/commit sql commands' do
expect(subscriber).to receive(:current_transaction)
.at_least(:once)
.and_return(transaction)
expect(transaction).not_to receive(:increment)
subscriber.sql(schema_event)
subscriber.sql(begin_event)
subscriber.sql(commit_event)
end
end
end
end
end
......@@ -40,4 +40,28 @@ RSpec.describe TriggerableHooks do
end
end
end
describe '.select_active' do
it 'returns hooks that match the active filter' do
TestableHook.create!(url: 'http://example1.com', push_events: true)
TestableHook.create!(url: 'http://example2.com', push_events: true)
filter1 = double(:filter1)
filter2 = double(:filter2)
allow(ActiveHookFilter).to receive(:new).exactly(2).times.and_return(filter1, filter2)
expect(filter1).to receive(:matches?).and_return(true)
expect(filter2).to receive(:matches?).and_return(false)
hooks = TestableHook.push_hooks.order_id_asc
expect(hooks.select_active(:push_hooks, {})).to eq [hooks.first]
end
it 'returns empty list if no hooks match the active filter' do
TestableHook.create!(url: 'http://example1.com', push_events: true)
filter = double(:filter)
allow(ActiveHookFilter).to receive(:new).and_return(filter)
expect(filter).to receive(:matches?).and_return(false)
expect(TestableHook.push_hooks.select_active(:push_hooks, {})).to eq []
end
end
end
require 'spec_helper'
describe ActiveHookFilter do
subject(:filter) { described_class.new(hook) }
describe '#matches?' do
context 'for push event hooks' do
let(:hook) do
create(:project_hook, push_events: true, push_events_branch_filter: branch_filter)
end
context 'branch filter is specified' do
let(:branch_filter) { 'master' }
it 'returns true if branch matches' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be true
end
it 'returns false if branch does not match' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/my_branch' })).to be false
end
it 'returns false if ref is nil' do
expect(filter.matches?(:push_hooks, {})).to be false
end
context 'branch filter contains wildcard' do
let(:branch_filter) { 'features/*' }
it 'returns true if branch matches' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/features/my-branch' })).to be true
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/features/my-branch/something' })).to be true
end
it 'returns false if branch does not match' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be false
end
end
end
context 'branch filter is not specified' do
let(:branch_filter) { nil }
it 'returns true' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be true
end
end
context 'branch filter is empty string' do
let(:branch_filter) { '' }
it 'acts like branch is not specified' do
expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be true
end
end
end
context 'for non-push-events hooks' do
let(:hook) do
create(:project_hook, issues_events: true, push_events: false, push_events_branch_filter: '')
end
it 'returns true as branch filters are not yet supported for these' do
expect(filter.matches?(:issues_events, { ref: 'refs/heads/master' })).to be true
end
end
end
end
......@@ -35,6 +35,26 @@ describe WebHook do
it { is_expected.not_to allow_values("foo\nbar", "foo\r\nbar").for(:token) }
end
describe 'push_events_branch_filter' do
it { is_expected.to allow_values("good_branch_name", "another/good-branch_name").for(:push_events_branch_filter) }
it { is_expected.to allow_values("").for(:push_events_branch_filter) }
it { is_expected.not_to allow_values("bad branch name", "bad~branchname").for(:push_events_branch_filter) }
it 'gets rid of whitespace' do
hook.push_events_branch_filter = ' branch '
hook.save
expect(hook.push_events_branch_filter).to eq('branch')
end
it 'stores whitespace only as empty' do
hook.push_events_branch_filter = ' '
hook.save
expect(hook.push_events_branch_filter).to eq('')
end
end
end
describe 'execute' do
......
......@@ -4049,21 +4049,45 @@ describe Project do
end
describe '#execute_hooks' do
it 'executes the projects hooks with the specified scope' do
hook1 = create(:project_hook, merge_requests_events: true, tag_push_events: false)
hook2 = create(:project_hook, merge_requests_events: false, tag_push_events: true)
project = create(:project, hooks: [hook1, hook2])
let(:data) { { ref: 'refs/heads/master', data: 'data' } }
it 'executes active projects hooks with the specified scope' do
hook = create(:project_hook, merge_requests_events: false, push_events: true)
expect(ProjectHook).to receive(:select_active)
.with(:push_hooks, data)
.and_return([hook])
project = create(:project, hooks: [hook])
expect_any_instance_of(ProjectHook).to receive(:async_execute).once
project.execute_hooks({}, :tag_push_hooks)
project.execute_hooks(data, :push_hooks)
end
it 'does not execute project hooks that dont match the specified scope' do
hook = create(:project_hook, merge_requests_events: true, push_events: false)
project = create(:project, hooks: [hook])
expect_any_instance_of(ProjectHook).not_to receive(:async_execute).once
project.execute_hooks(data, :push_hooks)
end
it 'does not execute project hooks which are not active' do
hook = create(:project_hook, push_events: true)
expect(ProjectHook).to receive(:select_active)
.with(:push_hooks, data)
.and_return([])
project = create(:project, hooks: [hook])
expect_any_instance_of(ProjectHook).not_to receive(:async_execute).once
project.execute_hooks(data, :push_hooks)
end
it 'executes the system hooks with the specified scope' do
expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with({ data: 'data' }, :merge_request_hooks)
expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with(data, :merge_request_hooks)
project = build(:project)
project.execute_hooks({ data: 'data' }, :merge_request_hooks)
project.execute_hooks(data, :merge_request_hooks)
end
it 'executes the system hooks when inside a transaction' do
......@@ -4078,7 +4102,7 @@ describe Project do
# actually get to the `after_commit` hook that queues these jobs.
expect do
project.transaction do
project.execute_hooks({ data: 'data' }, :merge_request_hooks)
project.execute_hooks(data, :merge_request_hooks)
end
end.not_to raise_error # Sidekiq::Worker::EnqueueFromTransactionError
end
......
......@@ -353,6 +353,15 @@ describe API::MergeRequests do
end
end
it 'returns the commits behind the target branch when include_diverged_commits_count is present' do
allow_any_instance_of(merge_request.class).to receive(:diverged_commits_count).and_return(1)
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), include_diverged_commits_count: true
expect(response).to have_gitlab_http_status(200)
expect(json_response['diverged_commits_count']).to eq(1)
end
it "returns a 404 error if merge_request_iid not found" do
get api("/projects/#{project.id}/merge_requests/999", user)
expect(response).to have_gitlab_http_status(404)
......
......@@ -9,7 +9,8 @@ describe API::ProjectHooks, 'ProjectHooks' do
:all_events_enabled,
project: project,
url: 'http://example.com',
enable_ssl_verification: true)
enable_ssl_verification: true,
push_events_branch_filter: 'master')
end
before do
......@@ -38,6 +39,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
expect(json_response.first['pipeline_events']).to eq(true)
expect(json_response.first['wiki_page_events']).to eq(true)
expect(json_response.first['enable_ssl_verification']).to eq(true)
expect(json_response.first['push_events_branch_filter']).to eq('master')
end
end
......@@ -90,7 +92,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
expect do
post api("/projects/#{project.id}/hooks", user),
url: "http://example.com", issues_events: true, confidential_issues_events: true, wiki_page_events: true,
job_events: true
job_events: true, push_events_branch_filter: 'some-feature-branch'
end.to change {project.hooks.count}.by(1)
expect(response).to have_gitlab_http_status(201)
......@@ -106,6 +108,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
expect(json_response['pipeline_events']).to eq(false)
expect(json_response['wiki_page_events']).to eq(true)
expect(json_response['enable_ssl_verification']).to eq(true)
expect(json_response['push_events_branch_filter']).to eq('some-feature-branch')
expect(json_response).not_to include('token')
end
......@@ -132,7 +135,12 @@ describe API::ProjectHooks, 'ProjectHooks' do
end
it "returns a 422 error if url not valid" do
post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com"
post api("/projects/#{project.id}/hooks", user), url: "ftp://example.com"
expect(response).to have_gitlab_http_status(422)
end
it "returns a 422 error if branch filter is not valid" do
post api("/projects/#{project.id}/hooks", user), url: "http://example.com", push_events_branch_filter: '~badbranchname/'
expect(response).to have_gitlab_http_status(422)
end
end
......
require 'spec_helper'
describe BranchFilterValidator do
let(:validator) { described_class.new(attributes: [:push_events_branch_filter]) }
let(:hook) { build(:project_hook) }
describe '#validates_each' do
it 'allows valid branch names' do
validator.validate_each(hook, :push_events_branch_filter, "good_branch_name")
validator.validate_each(hook, :push_events_branch_filter, "another/good_branch_name")
expect(hook.errors.empty?).to be true
end
it 'disallows bad branch names' do
validator.validate_each(hook, :push_events_branch_filter, "bad branch~name")
expect(hook.errors[:push_events_branch_filter].empty?).to be false
end
it 'allows wildcards' do
validator.validate_each(hook, :push_events_branch_filter, "features/*")
validator.validate_each(hook, :push_events_branch_filter, "features/*/bla")
validator.validate_each(hook, :push_events_branch_filter, "*-stable")
expect(hook.errors.empty?).to be true
end
it 'gets rid of whitespace' do
filter = ' master '
validator.validate_each(hook, :push_events_branch_filter, filter)
expect(filter).to eq 'master'
end
# Branch names can be quite long but in practice aren't over 255 so 4000 should
# be enough space for a list of branch names but we can increase if needed.
it 'limits length to 4000 chars' do
filter = 'a' * 4001
validator.validate_each(hook, :push_events_branch_filter, filter)
expect(hook.errors[:push_events_branch_filter].empty?).to be false
end
end
end
......@@ -7,10 +7,16 @@
@babel/template,7.0.0-beta.44,MIT
@babel/traverse,7.0.0-beta.44,MIT
@babel/types,7.0.0-beta.44,MIT
@gitlab-org/gitlab-svgs,1.27.0,SEE LICENSE IN LICENSE
@gitlab-org/gitlab-ui,1.0.5,UNKNOWN
@gitlab-org/gitlab-svgs,1.27.0,MIT
@gitlab-org/gitlab-svgs,1.28.0,MIT
@gitlab-org/gitlab-ui,1.0.5,MIT
@sindresorhus/is,0.7.0,MIT
@types/events,1.2.0,MIT
@types/glob,5.0.35,MIT
@types/jquery,2.0.48,MIT
@types/minimatch,3.0.3,MIT
@types/node,10.5.2,MIT
@types/parse5,5.0.0,MIT
@vue/component-compiler-utils,1.2.1,MIT
@webassemblyjs/ast,1.5.13,MIT
@webassemblyjs/floating-point-hex-parser,1.5.13,MIT
......@@ -214,7 +220,7 @@ big.js,3.1.3,MIT
binary-extensions,1.11.0,MIT
binaryextensions,2.1.1,MIT
bindata,2.4.3,ruby
bitsyntax,0.0.4,UNKNOWN
bitsyntax,0.0.4,MIT
bl,1.1.2,MIT
blackst0ne-mermaid,7.1.0-fixed,MIT
blob,0.0.4,MIT*
......@@ -300,8 +306,8 @@ clone-response,1.0.2,MIT
co,4.6.0,MIT
code-point-at,1.1.0,MIT
codesandbox-api,0.0.18,MIT
codesandbox-import-util-types,1.2.11,UNKNOWN
codesandbox-import-utils,1.2.11,UNKNOWN
codesandbox-import-util-types,1.2.11,LGPL
codesandbox-import-utils,1.2.11,LGPL
coercible,1.0.0,MIT
collection-visit,1.0.0,MIT
color-convert,1.9.1,MIT
......@@ -357,6 +363,7 @@ cryptiles,3.1.2,New BSD
crypto-browserify,3.12.0,MIT
crypto-random-string,1.0.0,MIT
css-loader,1.0.0,MIT
css-selector-parser,1.3.0,MIT
css-selector-tokenizer,0.7.0,MIT
css_parser,1.5.0,MIT
cssesc,0.1.0,MIT
......@@ -584,7 +591,7 @@ flush-write-stream,1.0.2,MIT
fog-aliyun,0.2.0,MIT
fog-aws,2.0.1,MIT
fog-core,1.45.0,MIT
fog-google,1.3.3,MIT
fog-google,1.7.1,MIT
fog-json,1.0.2,MIT
fog-local,0.3.1,MIT
fog-openstack,0.1.21,MIT
......@@ -625,9 +632,11 @@ get-uri,2.0.2,MIT
get-value,2.0.6,MIT
get_process_mem,0.2.0,MIT
getpass,0.1.7,MIT
gettext-extractor,3.3.2,MIT
gettext-extractor-vue,4.0.1,MIT
gettext_i18n_rails,1.8.0,MIT
gettext_i18n_rails_js,1.3.0,MIT
gitaly-proto,0.112.0,MIT
gitaly-proto,0.113.0,MIT
github-linguist,5.3.3,MIT
github-markup,1.7.0,MIT
gitlab-flowdock-git-hook,1.0.1,MIT
......@@ -649,7 +658,7 @@ globby,6.1.0,MIT
gollum-grit_adapter,1.0.1,MIT
gon,6.2.0,MIT
good-listener,1.2.2,MIT
google-api-client,0.19.8,Apache 2.0
google-api-client,0.23.4,Apache 2.0
google-protobuf,3.5.1,New BSD
googleapis-common-protos-types,1.0.1,Apache 2.0
googleauth,0.6.2,Apache 2.0
......@@ -845,6 +854,7 @@ jquery.waitforimages,2.2.0,MIT
js-cookie,2.1.3,MIT
js-tokens,3.0.2,MIT
js-yaml,3.11.0,MIT
js_regex,2.2.1,MIT
jsbn,0.1.1,MIT
jsesc,0.5.0,MIT
jsesc,1.3.0,MIT
......@@ -939,7 +949,7 @@ make-dir,1.2.0,MIT
mamacro,0.0.3,MIT
map-cache,0.2.2,MIT
map-obj,1.0.1,MIT
map-stream,0.1.0,UNKNOWN
map-stream,0.1.0,MIT
map-visit,1.0.0,MIT
marked,0.3.12,MIT
match-at,0.1.1,MIT
......@@ -952,7 +962,7 @@ memory-fs,0.4.1,MIT
meow,3.7.0,MIT
merge-descriptors,1.0.1,MIT
merge-source-map,1.1.0,MIT
method_source,0.8.2,MIT
method_source,0.9.0,MIT
methods,1.1.2,MIT
micromatch,3.1.10,MIT
miller-rabin,4.0.1,MIT
......@@ -1099,6 +1109,7 @@ pako,1.0.6,(MIT AND Zlib)
parallel-transform,1.1.0,MIT
parse-asn1,5.1.0,ISC
parse-json,2.2.0,MIT
parse5,5.0.0,MIT
parseqs,0.0.5,MIT
parseuri,0.0.5,MIT
parseurl,1.3.2,MIT
......@@ -1135,6 +1146,7 @@ pkg-dir,1.0.0,MIT
pkg-dir,2.0.0,MIT
pluralize,7.0.0,MIT
po_to_json,1.0.1,MIT
pofile,1.0.11,MIT
popper.js,1.14.3,MIT
portfinder,1.0.13,MIT
posix-character-classes,0.1.1,MIT
......@@ -1199,7 +1211,7 @@ rails-dom-testing,1.0.9,MIT
rails-html-sanitizer,1.0.4,MIT
rails-i18n,4.0.9,MIT
railties,4.2.10,MIT
rainbow,2.2.2,MIT
rainbow,3.0.0,MIT
raindrops,0.18.0,LGPL-2.1+
rake,12.3.1,MIT
randombytes,2.0.6,MIT
......@@ -1244,6 +1256,7 @@ regenerator-runtime,0.10.5,MIT
regenerator-runtime,0.11.0,MIT
regenerator-transform,0.10.1,BSD
regex-not,1.0.2,MIT
regexp_parser,0.5.0,MIT
regexpu-core,1.0.0,MIT
regexpu-core,2.0.0,MIT
registry-auth-token,3.3.2,MIT
......@@ -1275,13 +1288,13 @@ responselike,1.0.2,MIT
rest-client,2.0.2,MIT
restore-cursor,2.0.0,MIT
ret,0.1.15,MIT
retriable,3.1.1,MIT
retriable,3.1.2,MIT
right-align,0.1.3,MIT
rimraf,2.6.2,ISC
rinku,2.0.0,ISC
ripemd160,2.0.1,MIT
rotp,2.1.2,MIT
rouge,3.2.0,MIT
rouge,3.2.1,MIT
rqrcode,0.7.0,MIT
rqrcode-rails3,0.1.7,MIT
ruby-enum,0.7.2,MIT
......@@ -1293,7 +1306,7 @@ ruby_parser,3.9.0,MIT
rubyntlm,0.6.2,MIT
rubypants,0.2.0,BSD
rufus-scheduler,3.4.0,MIT
rugged,0.27.2,MIT
rugged,0.27.4,MIT
run-async,2.3.0,MIT
run-queue,1.0.3,ISC
rw,1.3.3,New BSD
......@@ -1352,7 +1365,7 @@ slash,1.0.0,MIT
slice-ansi,1.0.0,MIT
smart-buffer,1.1.15,MIT
smart-buffer,4.0.1,MIT
smooshpack,0.0.48,SEE LICENSE.MD IN ROOT
smooshpack,0.0.48,LGPL
smtp-connection,2.12.0,MIT
snapdragon,0.8.1,MIT
snapdragon-node,2.1.1,MIT
......@@ -1485,6 +1498,7 @@ tweetnacl,0.14.5,Unlicense
type-check,0.3.2,MIT
type-is,1.6.16,MIT
typedarray,0.0.6,MIT
typescript,2.9.2,Apache 2.0
tzinfo,1.2.5,MIT
u2f,0.2.1,MIT
uber,0.1.0,MIT
......
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