Commit a2da20e2 authored by Bob Van Landuyt's avatar Bob Van Landuyt

Merge branch '11060-bom-api-preliminary' into 'master'

Basic Rails implementation for Bill of Materials

Closes #11060

See merge request gitlab-org/gitlab-ee!11613
parents 434ef10a 7099b3d3
# frozen_string_literal: true
module Projects
class DependenciesController < Projects::ApplicationController
SORT_BY_PERMITTED_VALUES = %w(name type).freeze
SORT_PERMITTED_VALUES = %w(asc desc).freeze
before_action :ensure_bill_of_materials_feature_flag_enabled
def index
respond_to do |format|
format.json do
render json: paginated_dependecies
end
end
end
private
def ensure_bill_of_materials_feature_flag_enabled
render_404 unless Feature.enabled?(:bill_of_materials, default_enabled: false)
end
def found_dependencies
::Security::DependenciesFinder.new(project: @project, params: query_params).execute
end
def query_params
params.permit(:sort, :sort_by).delete_if do |key, value|
key == :sort_by && !value.in?(::Security::DependenciesFinder::SORT_BY_VALUES) ||
key == :sort && !value.in?(::Security::DependenciesFinder::SORT_VALUES)
end
end
# TODO: add proper implementation of edge cases handling
# format: { report: 'failed' }
# after we'll have more then just mock data
# reference: https://gitlab.com/gitlab-org/gitlab-ee/issues/10075#note_164915787
def paginated_dependecies
Kaminari.paginate_array(found_dependencies).page(params[:page])
end
end
end
# frozen_string_literal: true
module Security
class DependenciesFinder
attr_accessor :params
attr_reader :project
SORT_BY_VALUES = %w(name type).freeze
SORT_VALUES = %w(asc desc).freeze
# @param project [Project]
# @param [Hash] params to sort dependencies
# @option params ['asc', 'desc'] :sort ('asc') Order
# @option params ['name', 'type'] :sort_by ('name') Field to sort
def initialize(project:, params: {})
@project = project
@params = params
end
# @return [Array<Hash>] collection of found dependencies
def execute
collection = init_collection
collection = sort(collection)
collection
end
private
def init_collection
array = []
100.times { array << mock }
array
end
def fake_name
(0..16).map { ('a'..'z').to_a[rand 26] }.join
end
def mock
{
name: fake_name,
type: %w(gem npm module).sample,
location: {
blob_path: 'gitlab-org/gitlab-ee/blob/master/Gemfile.lock#L1248'
},
version: '5.4.1',
requirements: [
'~>5.4.1'
]
}
end
def sort(collection)
if @params[:sort_by] == 'type'
collection.sort_by! { |a| a[:type] }
else
collection.sort_by! { |a| a[:name] }
end
collection.reverse! if @params[:sort] == 'desc'
collection
end
end
end
---
title: Basic Rails implementation for BOM
merge_request: 11613
author:
type: added
...@@ -62,6 +62,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -62,6 +62,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end end
end end
resources :dependencies, only: [:index]
namespace :settings do namespace :settings do
resource :operations, only: [:show, :update] do resource :operations, only: [:show, :update] do
member do member do
......
# frozen_string_literal: true
require 'spec_helper'
describe Projects::DependenciesController do
describe 'GET index.json' do
set(:project) { create(:project, :repository, :public) }
set(:user) { create(:user) }
subject { get :index, params: { namespace_id: project.namespace, project_id: project }, format: :json }
before do
project.add_developer(user)
end
context 'with authorized user' do
before do
sign_in(user)
end
context 'when feature is available' do
it "returns a list of dependencies" do
subject
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an(Array)
expect(json_response.length).to eq 20
end
it 'returns paginated list' do
get :index, params: { namespace_id: project.namespace, project_id: project, page: 2 }, format: :json
expect(json_response.length).to eq 20
end
it 'returns sorted list' do
get :index, params: { namespace_id: project.namespace, project_id: project, sort_by: 'type', sort: 'desc' }, format: :json
sorted = json_response.sort_by { |a| a[:type] }.reverse
expect(json_response[0][:type]).to eq(sorted[0][:type])
expect(json_response[19][:type]).to eq(sorted[19][:type])
end
end
context 'when feature is disabled' do
before do
stub_feature_flags(bill_of_materials: false)
end
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(404)
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Security::DependenciesFinder do
describe '#execute' do
let(:project) { create :project }
subject { described_class.new(project: project, params: params).execute }
context 'without params' do
let(:params) { {} }
it 'returns array of data sorted by names' do
result = subject.sort_by { |a| a[:name] }
is_expected.to be_an(Array)
expect(subject.size).to eq(100)
expect(subject.first[:name]).to eq(result.first[:name])
expect(subject.last[:name]).to eq(result.last[:name])
end
end
context 'with params' do
context 'sorted desc by types' do
let(:params) do
{
sort: 'desc',
sort_by: 'type'
}
end
it 'returns array of data properly sorted' do
result = subject.sort_by { |a| a[:type] }.reverse
is_expected.to be_an(Array)
expect(subject.size).to eq(100)
expect(subject.first[:type]).to eq(result.first[:type])
expect(subject.last[:type]).to eq(result.last[:type])
end
end
end
end
end
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