Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c158fa8d69
commit
d47f9d2304
44 changed files with 368 additions and 297 deletions
|
@ -36,6 +36,8 @@ class GroupMembersFinder < UnionFinder
|
|||
relations << descendant_members
|
||||
end
|
||||
|
||||
return GroupMember.none if relations.empty?
|
||||
|
||||
members = find_union(relations, GroupMember)
|
||||
filter_members(members, params)
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
class Epic < ApplicationRecord
|
||||
include IgnorableColumns
|
||||
|
||||
ignore_column :milestone_id, remove_after: '2019-12-15', remove_with: '12.7'
|
||||
ignore_column :milestone_id, remove_after: '2020-02-01', remove_with: '12.8'
|
||||
|
||||
def self.link_reference_pattern
|
||||
nil
|
||||
|
|
|
@ -1325,7 +1325,7 @@ class Project < ApplicationRecord
|
|||
end
|
||||
|
||||
def has_active_hooks?(hooks_scope = :push_hooks)
|
||||
hooks.hooks_for(hooks_scope).any? || SystemHook.hooks_for(hooks_scope).any? || Gitlab::Plugin.any?
|
||||
hooks.hooks_for(hooks_scope).any? || SystemHook.hooks_for(hooks_scope).any? || Gitlab::FileHook.any?
|
||||
end
|
||||
|
||||
def has_active_services?(hooks_scope = :push_hooks)
|
||||
|
|
|
@ -14,8 +14,12 @@ class Snippet < ApplicationRecord
|
|||
include Editable
|
||||
include Gitlab::SQL::Pattern
|
||||
include FromUnion
|
||||
include IgnorableColumns
|
||||
|
||||
extend ::Gitlab::Utils::Override
|
||||
|
||||
ignore_column :storage_version, remove_with: '12.9', remove_after: '2020-03-22'
|
||||
|
||||
cache_markdown_field :title, pipeline: :single_line
|
||||
cache_markdown_field :description
|
||||
cache_markdown_field :content
|
||||
|
|
|
@ -14,7 +14,7 @@ class SystemHooksService
|
|||
hook.async_execute(data, 'system_hooks')
|
||||
end
|
||||
|
||||
Gitlab::Plugin.execute_all_async(data)
|
||||
Gitlab::FileHook.execute_all_async(data)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -11,4 +11,4 @@
|
|||
|
||||
= render 'shared/web_hooks/index', hooks: @hooks, hook_class: @hook.class
|
||||
|
||||
= render 'shared/plugins/index'
|
||||
= render 'shared/file_hooks/index'
|
||||
|
|
24
app/views/shared/file_hooks/_index.html.haml
Normal file
24
app/views/shared/file_hooks/_index.html.haml
Normal file
|
@ -0,0 +1,24 @@
|
|||
- file_hooks = Gitlab::FileHook.files
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-lg-4
|
||||
%h4.prepend-top-0
|
||||
= _('File Hooks')
|
||||
%p
|
||||
= _('File hooks are similar to system hooks but are executed as files instead of sending data to a URL.')
|
||||
= link_to _('For more information, see the File Hooks documentation.'), help_page_path('administration/file_hooks')
|
||||
|
||||
|
||||
.col-lg-8.append-bottom-default
|
||||
- if file_hooks.any?
|
||||
.card
|
||||
.card-header
|
||||
= _('File Hooks (%{count})') % { count: file_hooks.count }
|
||||
%ul.content-list
|
||||
- file_hooks.each do |file|
|
||||
%li
|
||||
.monospace
|
||||
= File.basename(file)
|
||||
- else
|
||||
.card.bg-light.text-center
|
||||
.nothing-here-block= _('No file hooks found.')
|
|
@ -1,23 +0,0 @@
|
|||
- plugins = Gitlab::Plugin.files
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-lg-4
|
||||
%h4.prepend-top-0
|
||||
Plugins
|
||||
%p
|
||||
#{link_to 'Plugins', help_page_path('administration/plugins')} are similar to
|
||||
system hooks but are executed as files instead of sending data to a URL.
|
||||
|
||||
.col-lg-8.append-bottom-default
|
||||
- if plugins.any?
|
||||
.card
|
||||
.card-header
|
||||
Plugins (#{plugins.count})
|
||||
%ul.content-list
|
||||
- plugins.each do |file|
|
||||
%li
|
||||
.monospace
|
||||
= File.basename(file)
|
||||
- else
|
||||
.card.bg-light.text-center
|
||||
.nothing-here-block No plugins found.
|
|
@ -158,7 +158,7 @@
|
|||
- pages
|
||||
- pages_domain_verification
|
||||
- pages_domain_ssl_renewal
|
||||
- plugin
|
||||
- file_hook
|
||||
- post_receive
|
||||
- process_commit
|
||||
- project_cache
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PluginWorker
|
||||
class FileHookWorker
|
||||
include ApplicationWorker
|
||||
|
||||
sidekiq_options retry: false
|
||||
feature_category :integrations
|
||||
|
||||
def perform(file_name, data)
|
||||
success, message = Gitlab::Plugin.execute(file_name, data)
|
||||
success, message = Gitlab::FileHook.execute(file_name, data)
|
||||
|
||||
unless success
|
||||
Gitlab::PluginLogger.error("Plugin Error => #{file_name}: #{message}")
|
||||
Gitlab::FileHookLogger.error("File Hook Error => #{file_name}: #{message}")
|
||||
end
|
||||
|
||||
true
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'Resolve Design View: Left/Right keyboard arrows through Designs'
|
||||
merge_request: 22870
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Add returning relation from GroupMembersFinder if called on root group with
|
||||
only inherited param
|
||||
merge_request: 23161
|
||||
author:
|
||||
type: fixed
|
5
changelogs/unreleased/22776-update-project-regex.yml
Normal file
5
changelogs/unreleased/22776-update-project-regex.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Allow Unicode 11 emojis in project names
|
||||
merge_request: 22776
|
||||
author: Harm Berntsen
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Added Conan installation instructions to Conan package details page
|
||||
merge_request: 22390
|
||||
author:
|
||||
type: added
|
5
changelogs/unreleased/dz-rename-plugins.yml
Normal file
5
changelogs/unreleased/dz-rename-plugins.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Rename GitLab Plugins feature to GitLab File Hooks
|
||||
merge_request: 22979
|
||||
author:
|
||||
type: changed
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Remove storage_version column from snippets
|
||||
merge_request: 23004
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove milestone_id from epics
|
||||
merge_request: 20539
|
||||
author: Lee Tickett
|
||||
type: other
|
|
@ -76,7 +76,7 @@
|
|||
- [pages_domain_ssl_renewal, 1]
|
||||
- [object_storage_upload, 1]
|
||||
- [object_storage, 1]
|
||||
- [plugin, 1]
|
||||
- [file_hook, 1]
|
||||
- [pipeline_background, 1]
|
||||
- [repository_update_remote_mirror, 1]
|
||||
- [repository_remove_remote, 1]
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveMilestoneIdFromEpics < ActiveRecord::Migration[5.2]
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
remove_column :epics, :milestone_id
|
||||
end
|
||||
|
||||
def down
|
||||
add_column :epics, :milestone_id, :integer
|
||||
end
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveStorageVersionColumnFromSnippets < ActiveRecord::Migration[5.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
return unless column_exists?(:snippets, :storage_version)
|
||||
|
||||
remove_column :snippets, :storage_version
|
||||
end
|
||||
|
||||
def down
|
||||
add_column_with_default( # rubocop:disable Migration/AddColumnWithDefault
|
||||
:snippets,
|
||||
:storage_version,
|
||||
:integer,
|
||||
default: 2,
|
||||
allow_null: false
|
||||
)
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2020_01_14_180546) do
|
||||
ActiveRecord::Schema.define(version: 2020_01_14_113341) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_trgm"
|
||||
|
@ -1538,7 +1538,6 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do
|
|||
end
|
||||
|
||||
create_table "epics", id: :serial, force: :cascade do |t|
|
||||
t.integer "milestone_id"
|
||||
t.integer "group_id", null: false
|
||||
t.integer "author_id", null: false
|
||||
t.integer "assignee_id"
|
||||
|
@ -1577,7 +1576,6 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do
|
|||
t.index ["end_date"], name: "index_epics_on_end_date"
|
||||
t.index ["group_id"], name: "index_epics_on_group_id"
|
||||
t.index ["iid"], name: "index_epics_on_iid"
|
||||
t.index ["milestone_id"], name: "index_milestone"
|
||||
t.index ["parent_id"], name: "index_epics_on_parent_id"
|
||||
t.index ["start_date"], name: "index_epics_on_start_date"
|
||||
t.index ["start_date_sourcing_epic_id"], name: "index_epics_on_start_date_sourcing_epic_id", where: "(start_date_sourcing_epic_id IS NOT NULL)"
|
||||
|
@ -3838,6 +3836,7 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do
|
|||
t.string "encrypted_secret_token_iv", limit: 255
|
||||
t.boolean "secret", default: false, null: false
|
||||
t.string "repository_storage", limit: 255, default: "default", null: false
|
||||
t.integer "storage_version", default: 2, null: false
|
||||
t.index ["author_id"], name: "index_snippets_on_author_id"
|
||||
t.index ["content"], name: "index_snippets_on_content_trigram", opclass: :gin_trgm_ops, using: :gin
|
||||
t.index ["created_at"], name: "index_snippets_on_created_at"
|
||||
|
@ -4590,7 +4589,6 @@ ActiveRecord::Schema.define(version: 2020_01_14_180546) do
|
|||
add_foreign_key "epics", "epics", column: "start_date_sourcing_epic_id", name: "fk_9d480c64b2", on_delete: :nullify
|
||||
add_foreign_key "epics", "milestones", column: "due_date_sourcing_milestone_id", name: "fk_3c1fd1cccc", on_delete: :nullify
|
||||
add_foreign_key "epics", "milestones", column: "start_date_sourcing_milestone_id", name: "fk_1fbed67632", on_delete: :nullify
|
||||
add_foreign_key "epics", "milestones", on_delete: :nullify
|
||||
add_foreign_key "epics", "namespaces", column: "group_id", name: "fk_f081aa4489", on_delete: :cascade
|
||||
add_foreign_key "epics", "users", column: "assignee_id", name: "fk_dccd3f98fc", on_delete: :nullify
|
||||
add_foreign_key "epics", "users", column: "author_id", name: "fk_3654b61b03", on_delete: :cascade
|
||||
|
|
|
@ -107,7 +107,7 @@ recorded:
|
|||
- Started/stopped user impersonation
|
||||
|
||||
It is possible to filter particular actions by choosing an audit data type from
|
||||
the filter drop-down. You can further filter by specific group, project or user
|
||||
the filter dropdown box. You can further filter by specific group, project or user
|
||||
(for authentication events).
|
||||
|
||||
![audit log](img/audit_log.png)
|
||||
|
|
116
doc/administration/file_hooks.md
Normal file
116
doc/administration/file_hooks.md
Normal file
|
@ -0,0 +1,116 @@
|
|||
# File hooks
|
||||
|
||||
> Introduced in GitLab 10.6.
|
||||
> Until 12.8 the feature name was Plugins.
|
||||
|
||||
With custom file hooks, GitLab administrators can introduce custom integrations
|
||||
without modifying GitLab's source code.
|
||||
|
||||
NOTE: **Note:**
|
||||
Instead of writing and supporting your own file hook you can make changes
|
||||
directly to the GitLab source code and contribute back upstream. This way we can
|
||||
ensure functionality is preserved across versions and covered by tests.
|
||||
|
||||
NOTE: **Note:**
|
||||
File hooks must be configured on the filesystem of the GitLab server. Only GitLab
|
||||
server administrators will be able to complete these tasks. Explore
|
||||
[system hooks] or [webhooks] as an option if you do not have filesystem access.
|
||||
|
||||
A file hook will run on each event so it's up to you to filter events or projects
|
||||
within a file hook code. You can have as many file hooks as you want. Each file hook will
|
||||
be triggered by GitLab asynchronously in case of an event. For a list of events
|
||||
see the [system hooks] documentation.
|
||||
|
||||
## Setup
|
||||
|
||||
The file hooks must be placed directly into the `plugins` directory, subdirectories
|
||||
will be ignored. There is an
|
||||
[`example` directory inside `plugins`](https://gitlab.com/gitlab-org/gitlab/tree/master/plugins/examples)
|
||||
where you can find some basic examples.
|
||||
|
||||
Follow the steps below to set up a custom hook:
|
||||
|
||||
1. On the GitLab server, navigate to the plugin directory.
|
||||
For an installation from source the path is usually
|
||||
`/home/git/gitlab/plugins/`. For Omnibus installs the path is
|
||||
usually `/opt/gitlab/embedded/service/gitlab-rails/plugins`.
|
||||
|
||||
For [highly available] configurations, your hook file should exist on each
|
||||
application server.
|
||||
|
||||
1. Inside the `plugins` directory, create a file with a name of your choice,
|
||||
without spaces or special characters.
|
||||
1. Make the hook file executable and make sure it's owned by the Git user.
|
||||
1. Write the code to make the file hook function as expected. That can be
|
||||
in any language, and ensure the 'shebang' at the top properly reflects the
|
||||
language type. For example, if the script is in Ruby the shebang will
|
||||
probably be `#!/usr/bin/env ruby`.
|
||||
1. The data to the file hook will be provided as JSON on STDIN. It will be exactly
|
||||
same as for [system hooks]
|
||||
|
||||
That's it! Assuming the file hook code is properly implemented, the hook will fire
|
||||
as appropriate. The file hooks file list is updated for each event, there is no
|
||||
need to restart GitLab to apply a new file hook.
|
||||
|
||||
If a file hook executes with non-zero exit code or GitLab fails to execute it, a
|
||||
message will be logged to:
|
||||
|
||||
- `gitlab-rails/plugin.log` in an Omnibus installation.
|
||||
- `log/plugin.log` in a source installation.
|
||||
|
||||
## Creating file hooks
|
||||
|
||||
Below is an example that will only response on the event `project_create` and
|
||||
will inform the admins from the GitLab instance that a new project has been created.
|
||||
|
||||
```ruby
|
||||
# By using the embedded ruby version we eliminate the possibility that our chosen language
|
||||
# would be unavailable from
|
||||
#!/opt/gitlab/embedded/bin/ruby
|
||||
require 'json'
|
||||
require 'mail'
|
||||
|
||||
# The incoming variables are in JSON format so we need to parse it first.
|
||||
ARGS = JSON.parse(STDIN.read)
|
||||
|
||||
# We only want to trigger this file hook on the event project_create
|
||||
return unless ARGS['event_name'] == 'project_create'
|
||||
|
||||
# We will inform our admins of our gitlab instance that a new project is created
|
||||
Mail.deliver do
|
||||
from 'info@gitlab_instance.com'
|
||||
to 'admin@gitlab_instance.com'
|
||||
subject "new project " + ARGS['name']
|
||||
body ARGS['owner_name'] + 'created project ' + ARGS['name']
|
||||
end
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
Writing your own file hook can be tricky and it's easier if you can check it
|
||||
without altering the system. A rake task is provided so that you can use it
|
||||
in a staging environment to test your file hook before using it in production.
|
||||
The rake task will use a sample data and execute each of file hook. The output
|
||||
should be enough to determine if the system sees your file hook and if it was
|
||||
executed without errors.
|
||||
|
||||
```bash
|
||||
# Omnibus installations
|
||||
sudo gitlab-rake file_hooks:validate
|
||||
|
||||
# Installations from source
|
||||
cd /home/git/gitlab
|
||||
bundle exec rake file_hooks:validate RAILS_ENV=production
|
||||
```
|
||||
|
||||
Example of output:
|
||||
|
||||
```
|
||||
Validating file hooks from /plugins directory
|
||||
* /home/git/gitlab/plugins/save_to_file.clj succeed (zero exit code)
|
||||
* /home/git/gitlab/plugins/save_to_file.rb failure (non-zero exit code)
|
||||
```
|
||||
|
||||
[system hooks]: ../system_hooks/system_hooks.md
|
||||
[webhooks]: ../user/project/integrations/webhooks.md
|
||||
[highly available]: ./high_availability/README.md
|
|
@ -245,7 +245,7 @@ To add a Prometheus dashboard for a single server GitLab setup:
|
|||
|
||||
1. Create a new data source in Grafana.
|
||||
1. Name your data source i.e GitLab.
|
||||
1. Select `Prometheus` in the type drop down.
|
||||
1. Select `Prometheus` in the type dropdown box.
|
||||
1. Add your Prometheus listen address as the URL and set access to `Browser`.
|
||||
1. Set the HTTP method to `GET`.
|
||||
1. Save & Test your configuration to verify that it works.
|
||||
|
|
|
@ -1,115 +1,5 @@
|
|||
# GitLab Plugin system
|
||||
---
|
||||
redirect_to: 'file_hooks.md'
|
||||
---
|
||||
|
||||
> Introduced in GitLab 10.6.
|
||||
|
||||
With custom plugins, GitLab administrators can introduce custom integrations
|
||||
without modifying GitLab's source code.
|
||||
|
||||
NOTE: **Note:**
|
||||
Instead of writing and supporting your own plugin you can make changes
|
||||
directly to the GitLab source code and contribute back upstream. This way we can
|
||||
ensure functionality is preserved across versions and covered by tests.
|
||||
|
||||
NOTE: **Note:**
|
||||
Plugins must be configured on the filesystem of the GitLab server. Only GitLab
|
||||
server administrators will be able to complete these tasks. Explore
|
||||
[system hooks] or [webhooks] as an option if you do not have filesystem access.
|
||||
|
||||
A plugin will run on each event so it's up to you to filter events or projects
|
||||
within a plugin code. You can have as many plugins as you want. Each plugin will
|
||||
be triggered by GitLab asynchronously in case of an event. For a list of events
|
||||
see the [system hooks] documentation.
|
||||
|
||||
## Setup
|
||||
|
||||
The plugins must be placed directly into the `plugins` directory, subdirectories
|
||||
will be ignored. There is an
|
||||
[`example` directory inside `plugins`](https://gitlab.com/gitlab-org/gitlab/tree/master/plugins/examples)
|
||||
where you can find some basic examples.
|
||||
|
||||
Follow the steps below to set up a custom hook:
|
||||
|
||||
1. On the GitLab server, navigate to the plugin directory.
|
||||
For an installation from source the path is usually
|
||||
`/home/git/gitlab/plugins/`. For Omnibus installs the path is
|
||||
usually `/opt/gitlab/embedded/service/gitlab-rails/plugins`.
|
||||
|
||||
For [highly available] configurations, your hook file should exist on each
|
||||
application server.
|
||||
|
||||
1. Inside the `plugins` directory, create a file with a name of your choice,
|
||||
without spaces or special characters.
|
||||
1. Make the hook file executable and make sure it's owned by the Git user.
|
||||
1. Write the code to make the plugin function as expected. That can be
|
||||
in any language, and ensure the 'shebang' at the top properly reflects the
|
||||
language type. For example, if the script is in Ruby the shebang will
|
||||
probably be `#!/usr/bin/env ruby`.
|
||||
1. The data to the plugin will be provided as JSON on STDIN. It will be exactly
|
||||
same as for [system hooks]
|
||||
|
||||
That's it! Assuming the plugin code is properly implemented, the hook will fire
|
||||
as appropriate. The plugins file list is updated for each event, there is no
|
||||
need to restart GitLab to apply a new plugin.
|
||||
|
||||
If a plugin executes with non-zero exit code or GitLab fails to execute it, a
|
||||
message will be logged to:
|
||||
|
||||
- `gitlab-rails/plugin.log` in an Omnibus installation.
|
||||
- `log/plugin.log` in a source installation.
|
||||
|
||||
## Creating plugins
|
||||
|
||||
Below is an example that will only response on the event `project_create` and
|
||||
will inform the admins from the GitLab instance that a new project has been created.
|
||||
|
||||
```ruby
|
||||
# By using the embedded ruby version we eliminate the possibility that our chosen language
|
||||
# would be unavailable from
|
||||
#!/opt/gitlab/embedded/bin/ruby
|
||||
require 'json'
|
||||
require 'mail'
|
||||
|
||||
# The incoming variables are in JSON format so we need to parse it first.
|
||||
ARGS = JSON.parse(STDIN.read)
|
||||
|
||||
# We only want to trigger this plugin on the event project_create
|
||||
return unless ARGS['event_name'] == 'project_create'
|
||||
|
||||
# We will inform our admins of our gitlab instance that a new project is created
|
||||
Mail.deliver do
|
||||
from 'info@gitlab_instance.com'
|
||||
to 'admin@gitlab_instance.com'
|
||||
subject "new project " + ARGS['name']
|
||||
body ARGS['owner_name'] + 'created project ' + ARGS['name']
|
||||
end
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
Writing your own plugin can be tricky and it's easier if you can check it
|
||||
without altering the system. A rake task is provided so that you can use it
|
||||
in a staging environment to test your plugin before using it in production.
|
||||
The rake task will use a sample data and execute each of plugin. The output
|
||||
should be enough to determine if the system sees your plugin and if it was
|
||||
executed without errors.
|
||||
|
||||
```bash
|
||||
# Omnibus installations
|
||||
sudo gitlab-rake plugins:validate
|
||||
|
||||
# Installations from source
|
||||
cd /home/git/gitlab
|
||||
bundle exec rake plugins:validate RAILS_ENV=production
|
||||
```
|
||||
|
||||
Example of output:
|
||||
|
||||
```
|
||||
Validating plugins from /plugins directory
|
||||
* /home/git/gitlab/plugins/save_to_file.clj succeed (zero exit code)
|
||||
* /home/git/gitlab/plugins/save_to_file.rb failure (non-zero exit code)
|
||||
```
|
||||
|
||||
[system hooks]: ../system_hooks/system_hooks.md
|
||||
[webhooks]: ../user/project/integrations/webhooks.md
|
||||
[highly available]: ./high_availability/README.md
|
||||
This document was moved to [File Hooks](file_hooks.md), after the Plugins feature was renamed to File Hooks.
|
||||
|
|
|
@ -44,7 +44,7 @@ To enable or disable GitLab CI/CD Pipelines in your project:
|
|||
|
||||
- **Private**: Only project members can access pipelines.
|
||||
- **Internal** or **Public**: Pipelines can be set to either **Only Project Members**
|
||||
or **Everyone With Access** via the drop-down box.
|
||||
or **Everyone With Access** via the dropdown box.
|
||||
|
||||
Press **Save changes** for the settings to take effect.
|
||||
|
||||
|
|
|
@ -244,7 +244,7 @@ Once the database is created, connect to your new RDS instance to verify access
|
|||
and to install a required extension.
|
||||
|
||||
You can find the host or endpoint by selecting the instance you just created and
|
||||
after the details drop down you'll find it labeled as 'Endpoint'. Do not to
|
||||
after the details dropdown menu you'll find it labeled as 'Endpoint'. Do not to
|
||||
include the colon and port number:
|
||||
|
||||
```sh
|
||||
|
|
|
@ -226,7 +226,7 @@ connections:
|
|||
![Azure - Add inbound security rules - HTTP](img/azure-add-inbound-sec-rule-http.png)
|
||||
|
||||
1. Enter **"HTTP"** in the `Name` field
|
||||
1. Select **HTTP** from the options in the `Service` drop-down
|
||||
1. Select **HTTP** from the options in the `Service` dropdown list
|
||||
1. Make sure the `Action` is set to **Allow**
|
||||
1. Click **"OK"**
|
||||
|
||||
|
@ -238,7 +238,7 @@ accept [SSH] connections:
|
|||
![Azure - Add inbound security rules - SSH](img/azure-add-inbound-sec-rule-ssh.png)
|
||||
|
||||
1. Enter **"SSH"** in the `Name` field
|
||||
1. Select **SSH** from the options in the `Service` drop-down
|
||||
1. Select **SSH** from the options in the `Service` dropdown list
|
||||
1. Make sure the `Action` is set to **Allow**
|
||||
1. Click **"OK"**
|
||||
|
||||
|
|
|
@ -269,6 +269,15 @@ it highlighted:
|
|||
}
|
||||
],
|
||||
"remediations": [
|
||||
{
|
||||
"fixes": [
|
||||
{
|
||||
"cve": "debian:9:apt:CVE-2019-3462"
|
||||
}
|
||||
],
|
||||
"summary": "Upgrade apt from 1.4.8 to 1.4.9",
|
||||
"diff": "YXB0LWdldCB1cGRhdGUgJiYgYXB0LWdldCB1cGdyYWRlIC15IGFwdA=="
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
@ -305,7 +314,11 @@ the report JSON unless stated otherwise. Presence of optional fields depends on
|
|||
| `vulnerabilities[].links` | An array of references to external documentation pieces or articles that describe the vulnerability further. Optional. |
|
||||
| `vulnerabilities[].links[].name` | Name of the vulnerability details link. Optional. |
|
||||
| `vulnerabilities[].links[].url` | URL of the vulnerability details document. Optional. |
|
||||
| `remediations` | Not supported yet. |
|
||||
| `remediations` | An array of objects containing information on cured vulnerabilities along with patch diffs to apply. Empty if no remediations provided by an underlying analyzer. |
|
||||
| `remediations[].fixes` | An array of strings that represent references to vulnerabilities fixed by this particular remediation. |
|
||||
| `remediations[].fixes[].cve` | A string value that describes a fixed vulnerability occurrence in the same format as `vulnerabilities[].cve`. |
|
||||
| `remediations[].summary` | Overview of how the vulnerabilities have been fixed. |
|
||||
| `remediations[].diff` | base64-encoded remediation code diff, compatible with [`git apply`](https://git-scm.com/docs/git-format-patch#_discussion). |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
@ -71,6 +71,8 @@ Designs cannot be added if the issue has been moved, or its
|
|||
## Viewing designs
|
||||
|
||||
Images on the Design Management page can be enlarged by clicking on them.
|
||||
You can navigate through designs by clicking on the navigation buttons on the
|
||||
top-right corner or with <kbd>Left</kbd>/<kbd>Right</kbd> keyboard buttons.
|
||||
|
||||
The number of comments on a design — if any — is listed to the right
|
||||
of the design filename. Clicking on this number enlarges the design
|
||||
|
|
|
@ -9,8 +9,7 @@ module Gitlab
|
|||
include SelfMonitoring::Helpers
|
||||
|
||||
steps :validate_self_monitoring_project_exists,
|
||||
:destroy_project_owner,
|
||||
:delete_project_id
|
||||
:destroy_project
|
||||
|
||||
def initialize
|
||||
super(nil)
|
||||
|
@ -30,29 +29,16 @@ module Gitlab
|
|||
success(result)
|
||||
end
|
||||
|
||||
def destroy_project_owner(result)
|
||||
def destroy_project(result)
|
||||
return success(result) unless project_created?
|
||||
|
||||
if self_monitoring_project.owner.destroy
|
||||
if self_monitoring_project.destroy
|
||||
success(result)
|
||||
else
|
||||
log_error(self_monitoring_project.errors.full_messages)
|
||||
error(_('Error deleting project. Check logs for error details.'))
|
||||
end
|
||||
end
|
||||
|
||||
def delete_project_id(result)
|
||||
update_result = application_settings.update(
|
||||
instance_administration_project_id: nil
|
||||
)
|
||||
|
||||
if update_result
|
||||
success(result)
|
||||
else
|
||||
log_error("Could not delete self monitoring project ID, errors: %{errors}" % { errors: application_settings.errors.full_messages })
|
||||
error(_('Could not delete project ID'))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Plugin
|
||||
module FileHook
|
||||
def self.any?
|
||||
plugin_glob.any? { |entry| File.file?(entry) }
|
||||
end
|
||||
|
@ -17,7 +17,7 @@ module Gitlab
|
|||
def self.execute_all_async(data)
|
||||
args = files.map { |file| [file, data] }
|
||||
|
||||
PluginWorker.bulk_perform_async(args)
|
||||
FileHookWorker.bulk_perform_async(args)
|
||||
end
|
||||
|
||||
def self.execute(file, data)
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
class PluginLogger < Gitlab::Logger
|
||||
class FileHookLogger < Gitlab::Logger
|
||||
def self.file_name_noext
|
||||
'plugin'
|
||||
end
|
|
@ -5,7 +5,7 @@ module Gitlab
|
|||
extend self
|
||||
|
||||
def project_name_regex
|
||||
@project_name_regex ||= /\A[\p{Alnum}\u{00A9}-\u{1f9c0}_][\p{Alnum}\p{Pd}\u{00A9}-\u{1f9c0}_\. ]*\z/.freeze
|
||||
@project_name_regex ||= /\A[\p{Alnum}\u{00A9}-\u{1f9ff}_][\p{Alnum}\p{Pd}\u{00A9}-\u{1f9ff}_\. ]*\z/.freeze
|
||||
end
|
||||
|
||||
def project_name_regex_message
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
namespace :plugins do
|
||||
namespace :file_hooks do
|
||||
desc 'Validate existing plugins'
|
||||
task validate: :environment do
|
||||
puts 'Validating plugins from /plugins directory'
|
||||
puts 'Validating file hooks from /plugins directory'
|
||||
|
||||
Gitlab::Plugin.files.each do |file|
|
||||
success, message = Gitlab::Plugin.execute(file, Gitlab::DataBuilder::Push::SAMPLE_DATA)
|
||||
Gitlab::FileHook.files.each do |file|
|
||||
success, message = Gitlab::FileHook.execute(file, Gitlab::DataBuilder::Push::SAMPLE_DATA)
|
||||
|
||||
if success
|
||||
puts "* #{file} succeed (zero exit code)."
|
|
@ -5187,9 +5187,6 @@ msgstr ""
|
|||
msgid "Could not delete chat nickname %{chat_name}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Could not delete project ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "Could not fetch projects"
|
||||
msgstr ""
|
||||
|
||||
|
@ -7992,6 +7989,12 @@ msgstr ""
|
|||
msgid "Fetching licenses failed. You are not permitted to perform this action."
|
||||
msgstr ""
|
||||
|
||||
msgid "File Hooks"
|
||||
msgstr ""
|
||||
|
||||
msgid "File Hooks (%{count})"
|
||||
msgstr ""
|
||||
|
||||
msgid "File added"
|
||||
msgstr ""
|
||||
|
||||
|
@ -8001,6 +8004,9 @@ msgstr ""
|
|||
msgid "File deleted"
|
||||
msgstr ""
|
||||
|
||||
msgid "File hooks are similar to system hooks but are executed as files instead of sending data to a URL."
|
||||
msgstr ""
|
||||
|
||||
msgid "File mode changed from %{a_mode} to %{b_mode}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -8166,6 +8172,9 @@ msgstr ""
|
|||
msgid "For more information, please review %{link_start_tag}Jaeger's configuration doc%{link_end_tag}"
|
||||
msgstr ""
|
||||
|
||||
msgid "For more information, see the File Hooks documentation."
|
||||
msgstr ""
|
||||
|
||||
msgid "For more information, see the documentation on %{deactivating_usage_ping_link_start}deactivating the usage ping%{deactivating_usage_ping_link_end}."
|
||||
msgstr ""
|
||||
|
||||
|
@ -12203,6 +12212,9 @@ msgstr ""
|
|||
msgid "No file chosen"
|
||||
msgstr ""
|
||||
|
||||
msgid "No file hooks found."
|
||||
msgstr ""
|
||||
|
||||
msgid "No file selected"
|
||||
msgstr ""
|
||||
|
||||
|
@ -12775,6 +12787,18 @@ msgstr ""
|
|||
msgid "Package was removed"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Add Conan Remote"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Conan Command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Copy Conan Command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Copy Conan Setup Command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Copy Maven XML"
|
||||
msgstr ""
|
||||
|
||||
|
@ -12805,6 +12829,9 @@ msgstr ""
|
|||
msgid "PackageRegistry|Delete package"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|For more information on the Conan registry, %{linkStart}see the documentation%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|For more information on the Maven registry, %{linkStart}see the documentation%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
|
@ -18642,6 +18669,9 @@ msgstr ""
|
|||
msgid "There was an error while fetching cycle analytics duration data."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was an error while fetching cycle analytics duration median data."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was an error while fetching cycle analytics summary data."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -28,11 +28,11 @@ describe 'Admin::Hooks' do
|
|||
end
|
||||
|
||||
it 'renders plugins list as well' do
|
||||
allow(Gitlab::Plugin).to receive(:files).and_return(['foo.rb', 'bar.clj'])
|
||||
allow(Gitlab::FileHook).to receive(:files).and_return(['foo.rb', 'bar.clj'])
|
||||
|
||||
visit admin_hooks_path
|
||||
|
||||
expect(page).to have_content('Plugins')
|
||||
expect(page).to have_content('File Hooks')
|
||||
expect(page).to have_content('foo.rb')
|
||||
expect(page).to have_content('bar.clj')
|
||||
end
|
||||
|
|
|
@ -59,8 +59,8 @@ describe 'Projects > Settings > User renames a project' do
|
|||
|
||||
context 'with emojis' do
|
||||
it 'shows error for invalid project name' do
|
||||
change_name(project, '🚀 foo bar ☁️')
|
||||
expect(page).to have_field 'Project name', with: '🚀 foo bar ☁️'
|
||||
change_name(project, '🧮 foo bar ☁️')
|
||||
expect(page).to have_field 'Project name', with: '🧮 foo bar ☁️'
|
||||
expect(page).not_to have_content "Name can contain only letters, digits, emojis '_', '.', dash and space. It must start with letter, digit, emoji or '_'."
|
||||
end
|
||||
end
|
||||
|
|
|
@ -57,6 +57,14 @@ describe GroupMembersFinder, '#execute' do
|
|||
expect(result.to_a).to match_array([member1])
|
||||
end
|
||||
|
||||
it 'does not return nil if `inherited only` relation is requested on root group' do
|
||||
group.add_developer(user2)
|
||||
|
||||
result = described_class.new(group).execute(include_relations: [:inherited])
|
||||
|
||||
expect(result).not_to be_nil
|
||||
end
|
||||
|
||||
it 'returns members for descendant groups if requested' do
|
||||
member1 = group.add_maintainer(user2)
|
||||
member2 = group.add_maintainer(user1)
|
||||
|
@ -71,25 +79,41 @@ describe GroupMembersFinder, '#execute' do
|
|||
|
||||
it 'returns searched members if requested' do
|
||||
group.add_maintainer(user2)
|
||||
nested_group.add_maintainer(user2)
|
||||
nested_group.add_maintainer(user3)
|
||||
nested_group.add_maintainer(user4)
|
||||
group.add_developer(user3)
|
||||
member = group.add_maintainer(user1)
|
||||
|
||||
result = described_class.new(group).execute(include_relations: [:direct, :descendants], params: { search: user1.name })
|
||||
result = described_class.new(group).execute(params: { search: user1.name })
|
||||
|
||||
expect(result.to_a).to match_array([member])
|
||||
end
|
||||
|
||||
it 'returns nothing if search only in inherited relation' do
|
||||
group.add_maintainer(user2)
|
||||
group.add_developer(user3)
|
||||
group.add_maintainer(user1)
|
||||
|
||||
result = described_class.new(group).execute(include_relations: [:inherited], params: { search: user1.name })
|
||||
|
||||
expect(result.to_a).to match_array([])
|
||||
end
|
||||
|
||||
it 'returns searched member only from nested_group if search only in inherited relation' do
|
||||
group.add_maintainer(user2)
|
||||
group.add_developer(user3)
|
||||
nested_group.add_maintainer(create(:user, name: user1.name))
|
||||
member = group.add_maintainer(user1)
|
||||
|
||||
result = described_class.new(nested_group).execute(include_relations: [:inherited], params: { search: member.user.name })
|
||||
|
||||
expect(result.to_a).to contain_exactly(member)
|
||||
end
|
||||
|
||||
it 'returns members with two-factor auth if requested by owner' do
|
||||
group.add_owner(user2)
|
||||
group.add_maintainer(user1)
|
||||
nested_group.add_maintainer(user2)
|
||||
nested_group.add_maintainer(user3)
|
||||
nested_group.add_maintainer(user4)
|
||||
member = group.add_maintainer(user5)
|
||||
|
||||
result = described_class.new(group, user2).execute(include_relations: [:direct, :descendants], params: { two_factor: 'enabled' })
|
||||
result = described_class.new(group, user2).execute(params: { two_factor: 'enabled' })
|
||||
|
||||
expect(result.to_a).to contain_exactly(member)
|
||||
end
|
||||
|
@ -97,14 +121,11 @@ describe GroupMembersFinder, '#execute' do
|
|||
it 'returns members without two-factor auth if requested by owner' do
|
||||
member1 = group.add_owner(user2)
|
||||
member2 = group.add_maintainer(user1)
|
||||
nested_group.add_maintainer(user2)
|
||||
member3 = nested_group.add_maintainer(user3)
|
||||
member4 = nested_group.add_maintainer(user4)
|
||||
member_with_2fa = group.add_maintainer(user5)
|
||||
|
||||
result = described_class.new(group, user2).execute(include_relations: [:direct, :descendants], params: { two_factor: 'disabled' })
|
||||
result = described_class.new(group, user2).execute(params: { two_factor: 'disabled' })
|
||||
|
||||
expect(result.to_a).not_to include(member_with_2fa)
|
||||
expect(result.to_a).to match_array([member1, member2, member3, member4])
|
||||
expect(result.to_a).to match_array([member1, member2])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,12 +4,8 @@ require 'spec_helper'
|
|||
|
||||
describe Gitlab::DatabaseImporters::SelfMonitoring::Project::DeleteService do
|
||||
describe '#execute' do
|
||||
let!(:application_setting) { create(:application_setting) }
|
||||
let(:result) { subject.execute }
|
||||
let(:application_setting) { Gitlab::CurrentSettings.current_application_settings }
|
||||
|
||||
before do
|
||||
allow(ApplicationSetting).to receive(:current_without_cache) { application_setting }
|
||||
end
|
||||
|
||||
context 'when project does not exist' do
|
||||
it 'returns error' do
|
||||
|
@ -21,24 +17,16 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::DeleteService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with project destroyed but ID still present in application settings' do
|
||||
before do
|
||||
application_setting.instance_administration_project_id = 1
|
||||
end
|
||||
|
||||
it 'deletes project ID from application settings' do
|
||||
subject.execute
|
||||
|
||||
expect(application_setting.instance_administration_project_id).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when self monitoring project exists' do
|
||||
let(:group) { create(:group) }
|
||||
let(:project) { create(:project, namespace: group) }
|
||||
|
||||
before do
|
||||
application_setting.instance_administration_project = project
|
||||
let(:application_setting) do
|
||||
create(
|
||||
:application_setting,
|
||||
instance_administration_project_id: project.id,
|
||||
instance_administrators_group_id: group.id
|
||||
)
|
||||
end
|
||||
|
||||
it 'destroys project' do
|
||||
|
@ -50,7 +38,13 @@ describe Gitlab::DatabaseImporters::SelfMonitoring::Project::DeleteService do
|
|||
it 'deletes project ID from application settings' do
|
||||
subject.execute
|
||||
|
||||
expect(application_setting.instance_administration_project_id).to be_nil
|
||||
expect(application_setting.reload.instance_administration_project_id).to be_nil
|
||||
end
|
||||
|
||||
it 'does not delete group' do
|
||||
subject.execute
|
||||
|
||||
expect(application_setting.instance_administrators_group).to eq(group)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Plugin do
|
||||
let(:plugin) { Rails.root.join('plugins', 'test.rb') }
|
||||
let(:tmp_file) { Tempfile.new('plugin-dump') }
|
||||
describe Gitlab::FileHook do
|
||||
let(:file_hook) { Rails.root.join('plugins', 'test.rb') }
|
||||
let(:tmp_file) { Tempfile.new('file_hook-dump') }
|
||||
|
||||
let(:plugin_source) do
|
||||
let(:file_hook_source) do
|
||||
<<~EOS
|
||||
#!/usr/bin/env ruby
|
||||
x = STDIN.read
|
||||
|
@ -14,13 +14,13 @@ describe Gitlab::Plugin do
|
|||
EOS
|
||||
end
|
||||
|
||||
context 'with plugins present' do
|
||||
context 'with file_hooks present' do
|
||||
before do
|
||||
File.write(plugin, plugin_source)
|
||||
File.write(file_hook, file_hook_source)
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm(plugin)
|
||||
FileUtils.rm(file_hook)
|
||||
end
|
||||
|
||||
describe '.any?' do
|
||||
|
@ -30,13 +30,13 @@ describe Gitlab::Plugin do
|
|||
end
|
||||
|
||||
describe '.files?' do
|
||||
it 'returns a list of plugins' do
|
||||
expect(described_class.files).to match_array([plugin.to_s])
|
||||
it 'returns a list of file_hooks' do
|
||||
expect(described_class.files).to match_array([file_hook.to_s])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without any plugins' do
|
||||
context 'without any file_hooks' do
|
||||
describe '.any?' do
|
||||
it 'returns false' do
|
||||
expect(described_class.any?).to be false
|
||||
|
@ -52,21 +52,21 @@ describe Gitlab::Plugin do
|
|||
|
||||
describe '.execute' do
|
||||
let(:data) { Gitlab::DataBuilder::Push::SAMPLE_DATA }
|
||||
let(:result) { described_class.execute(plugin.to_s, data) }
|
||||
let(:result) { described_class.execute(file_hook.to_s, data) }
|
||||
let(:success) { result.first }
|
||||
let(:message) { result.last }
|
||||
|
||||
before do
|
||||
File.write(plugin, plugin_source)
|
||||
File.write(file_hook, file_hook_source)
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm(plugin)
|
||||
FileUtils.rm(file_hook)
|
||||
end
|
||||
|
||||
context 'successful execution' do
|
||||
before do
|
||||
File.chmod(0o777, plugin)
|
||||
File.chmod(0o777, file_hook)
|
||||
end
|
||||
|
||||
after do
|
||||
|
@ -76,7 +76,7 @@ describe Gitlab::Plugin do
|
|||
it { expect(success).to be true }
|
||||
it { expect(message).to be_empty }
|
||||
|
||||
it 'ensures plugin received data via stdin' do
|
||||
it 'ensures file_hook received data via stdin' do
|
||||
result
|
||||
|
||||
expect(File.read(tmp_file.path)).to eq(data.to_json)
|
||||
|
@ -89,7 +89,7 @@ describe Gitlab::Plugin do
|
|||
end
|
||||
|
||||
context 'non-zero exit' do
|
||||
let(:plugin_source) do
|
||||
let(:file_hook_source) do
|
||||
<<~EOS
|
||||
#!/usr/bin/env ruby
|
||||
exit 1
|
||||
|
@ -97,7 +97,7 @@ describe Gitlab::Plugin do
|
|||
end
|
||||
|
||||
before do
|
||||
File.chmod(0o777, plugin)
|
||||
File.chmod(0o777, file_hook)
|
||||
end
|
||||
|
||||
it { expect(success).to be false }
|
|
@ -4745,7 +4745,7 @@ describe Project do
|
|||
end
|
||||
|
||||
it 'returns true when a plugin exists' do
|
||||
expect(Gitlab::Plugin).to receive(:any?).twice.and_return(true)
|
||||
expect(Gitlab::FileHook).to receive(:any?).twice.and_return(true)
|
||||
|
||||
expect(project.has_active_hooks?(:merge_request_events)).to be_truthy
|
||||
expect(project.has_active_hooks?).to be_truthy
|
||||
|
|
27
spec/workers/file_hook_worker_spec.rb
Normal file
27
spec/workers/file_hook_worker_spec.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe FileHookWorker do
|
||||
include RepoHelpers
|
||||
|
||||
let(:filename) { 'my_file_hook.rb' }
|
||||
let(:data) { { 'event_name' => 'project_create' } }
|
||||
|
||||
subject { described_class.new }
|
||||
|
||||
describe '#perform' do
|
||||
it 'executes Gitlab::FileHook with expected values' do
|
||||
allow(Gitlab::FileHook).to receive(:execute).with(filename, data).and_return([true, ''])
|
||||
|
||||
expect(subject.perform(filename, data)).to be_truthy
|
||||
end
|
||||
|
||||
it 'logs message in case of file_hook execution failure' do
|
||||
allow(Gitlab::FileHook).to receive(:execute).with(filename, data).and_return([false, 'permission denied'])
|
||||
|
||||
expect(Gitlab::FileHookLogger).to receive(:error)
|
||||
expect(subject.perform(filename, data)).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe PluginWorker do
|
||||
include RepoHelpers
|
||||
|
||||
let(:filename) { 'my_plugin.rb' }
|
||||
let(:data) { { 'event_name' => 'project_create' } }
|
||||
|
||||
subject { described_class.new }
|
||||
|
||||
describe '#perform' do
|
||||
it 'executes Gitlab::Plugin with expected values' do
|
||||
allow(Gitlab::Plugin).to receive(:execute).with(filename, data).and_return([true, ''])
|
||||
|
||||
expect(subject.perform(filename, data)).to be_truthy
|
||||
end
|
||||
|
||||
it 'logs message in case of plugin execution failure' do
|
||||
allow(Gitlab::Plugin).to receive(:execute).with(filename, data).and_return([false, 'permission denied'])
|
||||
|
||||
expect(Gitlab::PluginLogger).to receive(:error)
|
||||
expect(subject.perform(filename, data)).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue