Commit 1d415d4f authored by Tetiana Chupryna's avatar Tetiana Chupryna Committed by Mayra Cabrera

Return dependency list with status

Change response schema and return not only a list of dependencies
but status and ci job path.
As well, replased mock data with dependency list report data.
parent caa32a6a
......@@ -3,42 +3,43 @@
module Projects
module Security
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
before_action :ensure_dependency_list_feature_available
def index
respond_to do |format|
format.json do
render json: paginated_dependecies
render json: paginated_dependencies
end
end
end
private
def ensure_bill_of_materials_feature_flag_enabled
render_404 unless Feature.enabled?(:bill_of_materials, default_enabled: false)
def ensure_dependency_list_feature_available
render_404 unless project.feature_available?(:dependency_list)
end
def found_dependencies
::Security::DependenciesFinder.new(project: @project, params: query_params).execute
@dependencies ||= pipeline ? service.execute : []
end
def paginated_dependencies
params[:page] ? Kaminari.paginate_array(found_dependencies).page(params[:page]) : found_dependencies
end
def pipeline
@pipeline ||= project.all_pipelines.latest_successful_for(project.default_branch)
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)
key == :sort_by && !value.in?(::Security::DependencyListService::SORT_BY_VALUES) ||
key == :sort && !value.in?(::Security::DependencyListService::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])
def service
::Security::DependencyListService.new(pipeline: pipeline, params: query_params)
end
end
end
......
# frozen_string_literal: true
module Security
class DependenciesFinder
attr_accessor :params
attr_reader :project
SORT_BY_VALUES = %w(name type).freeze
class DependencyListService
SORT_BY_VALUES = %w(name packager).freeze
SORT_VALUES = %w(asc desc).freeze
# @param project [Project]
# @param pipeline [Ci::Pipeline]
# @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
# @option params ['name', 'packager'] :sort_by ('name') Field to sort
def initialize(pipeline:, params: {})
@pipeline = pipeline
@params = params
end
......@@ -26,33 +23,15 @@ module Security
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
attr_accessor :params, :pipeline
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'
]
}
def init_collection
pipeline.dependency_list_report.dependencies
end
def sort(collection)
if @params[:sort_by] == 'type'
collection.sort_by! { |a| a[:type] }
if @params[:sort_by] == 'packager'
collection.sort_by! { |a| a[:packager] }
else
collection.sort_by! { |a| a[:name] }
end
......
---
title: Use real data in `:project/security/dependencies` endpoint
merge_request: 13906
author:
type: changed
......@@ -19,35 +19,42 @@ describe Projects::Security::DependenciesController do
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
before do
stub_licensed_features(dependency_list: true)
end
it 'returns paginated list' do
get :index, params: { namespace_id: project.namespace, project_id: project, page: 2 }, format: :json
context 'with existing report' do
let!(:pipeline) { create(:ee_ci_pipeline, :with_dependency_list_report, project: project) }
expect(json_response.length).to eq 20
end
context 'without pagination params' do
it "returns a list of dependencies" do
subject
it 'returns sorted list' do
get :index, params: { namespace_id: project.namespace, project_id: project, sort_by: 'type', sort: 'desc' }, format: :json
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_a(Array)
expect(json_response.length).to eq(21)
end
end
sorted = json_response.sort_by { |a| a[:type] }.reverse
context 'with params' do
it 'returns paginated list' do
get :index, params: { namespace_id: project.namespace, project_id: project, page: 2 }, format: :json
expect(json_response[0][:type]).to eq(sorted[0][:type])
expect(json_response[19][:type]).to eq(sorted[19][:type])
end
end
expect(json_response.length).to eq(1)
end
context 'when feature is disabled' do
before do
stub_feature_flags(bill_of_materials: false)
it 'returns sorted list' do
get :index, params: { namespace_id: project.namespace, project_id: project, sort_by: 'packager', sort: 'desc', page: 1 }, format: :json
expect(json_response.length).to eq(20)
expect(json_response[0]['packager']).to eq('Ruby (Bundler)')
expect(json_response[19]['packager']).to eq('JavaScript (Yarn)')
end
end
end
end
context 'when feature is not available' do
it 'returns 404' do
subject
......@@ -55,5 +62,13 @@ describe Projects::Security::DependenciesController do
end
end
end
context 'with unauthorized user' do
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(404)
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
# frozen_string_literal: true
require 'spec_helper'
describe Security::DependencyListService do
describe '#execute' do
let!(:pipeline) { create(:ee_ci_pipeline, :with_dependency_list_report) }
subject { described_class.new(pipeline: pipeline, params: params).execute }
before do
stub_licensed_features(dependency_list: true)
end
context 'without params' do
let(:params) { {} }
it 'returns array of dependencies' do
is_expected.to be_an(Array)
end
it 'is sorted by names by default' do
expect(subject.size).to eq(21)
expect(subject.first[:name]).to eq('async')
expect(subject.last[:name]).to eq('xpath.js')
end
end
context 'with params' do
context 'sorted desc by packagers' do
let(:params) do
{
sort: 'desc',
sort_by: 'packager'
}
end
it 'returns array of data properly sorted' do
expect(subject.first[:packager]).to eq('Ruby (Bundler)')
expect(subject.last[:packager]).to eq('JavaScript (Yarn)')
end
end
context 'sorted asc by packagers' do
let(:params) do
{
sort: 'asc',
sort_by: 'packager'
}
end
it 'returns array of data properly sorted' do
expect(subject.first[:packager]).to eq('JavaScript (Yarn)')
expect(subject.last[:packager]).to eq('Ruby (Bundler)')
end
end
context 'sorted desc by names' do
let(:params) do
{
sort: 'desc',
sort_by: 'name'
}
end
it 'returns array of data properly sorted' do
expect(subject.first[:name]).to eq('xpath.js')
expect(subject.last[:name]).to eq('async')
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