Merge branch 'feature/view-related-serializers' into 'master'
Add serializer for environments ## What does this MR do? This will make it possible to create a payload need in https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7015 for use with Vue. ## Why was this MR needed? Closes #23886 See merge request !7174
This commit is contained in:
commit
5a0a4506d2
16 changed files with 343 additions and 0 deletions
18
app/serializers/base_serializer.rb
Normal file
18
app/serializers/base_serializer.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
class BaseSerializer
|
||||
def initialize(parameters = {})
|
||||
@request = EntityRequest.new(parameters)
|
||||
end
|
||||
|
||||
def represent(resource, opts = {})
|
||||
self.class.entity_class
|
||||
.represent(resource, opts.merge(request: @request))
|
||||
end
|
||||
|
||||
def self.entity(entity_class)
|
||||
@entity_class ||= entity_class
|
||||
end
|
||||
|
||||
def self.entity_class
|
||||
@entity_class
|
||||
end
|
||||
end
|
24
app/serializers/build_entity.rb
Normal file
24
app/serializers/build_entity.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
class BuildEntity < Grape::Entity
|
||||
include RequestAwareEntity
|
||||
|
||||
expose :id
|
||||
expose :name
|
||||
|
||||
expose :build_url do |build|
|
||||
url_to(:namespace_project_build, build)
|
||||
end
|
||||
|
||||
expose :retry_url do |build|
|
||||
url_to(:retry_namespace_project_build, build)
|
||||
end
|
||||
|
||||
expose :play_url, if: ->(build, _) { build.manual? } do |build|
|
||||
url_to(:play_namespace_project_build, build)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def url_to(route, build)
|
||||
send("#{route}_url", build.project.namespace, build.project, build)
|
||||
end
|
||||
end
|
12
app/serializers/commit_entity.rb
Normal file
12
app/serializers/commit_entity.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
class CommitEntity < API::Entities::RepoCommit
|
||||
include RequestAwareEntity
|
||||
|
||||
expose :author, using: UserEntity
|
||||
|
||||
expose :commit_url do |commit|
|
||||
namespace_project_tree_url(
|
||||
request.project.namespace,
|
||||
request.project,
|
||||
id: commit.id)
|
||||
end
|
||||
end
|
27
app/serializers/deployment_entity.rb
Normal file
27
app/serializers/deployment_entity.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
class DeploymentEntity < Grape::Entity
|
||||
include RequestAwareEntity
|
||||
|
||||
expose :id
|
||||
expose :iid
|
||||
expose :sha
|
||||
|
||||
expose :ref do
|
||||
expose :name do |deployment|
|
||||
deployment.ref
|
||||
end
|
||||
|
||||
expose :ref_url do |deployment|
|
||||
namespace_project_tree_url(
|
||||
deployment.project.namespace,
|
||||
deployment.project,
|
||||
id: deployment.ref)
|
||||
end
|
||||
end
|
||||
|
||||
expose :tag
|
||||
expose :last?
|
||||
expose :user, using: UserEntity
|
||||
expose :commit, using: CommitEntity
|
||||
expose :deployable, using: BuildEntity
|
||||
expose :manual_actions, using: BuildEntity
|
||||
end
|
12
app/serializers/entity_request.rb
Normal file
12
app/serializers/entity_request.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
class EntityRequest
|
||||
# We use EntityRequest object to collect parameters and variables
|
||||
# from the controller. Because options that are being passed to the entity
|
||||
# do appear in each entity object in the chain, we need a way to pass data
|
||||
# that is present in the controller (see #20045).
|
||||
#
|
||||
def initialize(parameters)
|
||||
parameters.each do |key, value|
|
||||
define_singleton_method(key) { value }
|
||||
end
|
||||
end
|
||||
end
|
20
app/serializers/environment_entity.rb
Normal file
20
app/serializers/environment_entity.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
class EnvironmentEntity < Grape::Entity
|
||||
include RequestAwareEntity
|
||||
|
||||
expose :id
|
||||
expose :name
|
||||
expose :state
|
||||
expose :external_url
|
||||
expose :environment_type
|
||||
expose :last_deployment, using: DeploymentEntity
|
||||
expose :stoppable?
|
||||
|
||||
expose :environment_url do |environment|
|
||||
namespace_project_environment_url(
|
||||
environment.project.namespace,
|
||||
environment.project,
|
||||
environment)
|
||||
end
|
||||
|
||||
expose :created_at, :updated_at
|
||||
end
|
3
app/serializers/environment_serializer.rb
Normal file
3
app/serializers/environment_serializer.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class EnvironmentSerializer < BaseSerializer
|
||||
entity EnvironmentEntity
|
||||
end
|
11
app/serializers/request_aware_entity.rb
Normal file
11
app/serializers/request_aware_entity.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
module RequestAwareEntity
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
include Gitlab::Routing.url_helpers
|
||||
end
|
||||
|
||||
def request
|
||||
@options.fetch(:request)
|
||||
end
|
||||
end
|
2
app/serializers/user_entity.rb
Normal file
2
app/serializers/user_entity.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
class UserEntity < API::Entities::UserBasic
|
||||
end
|
31
spec/serializers/build_entity_spec.rb
Normal file
31
spec/serializers/build_entity_spec.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe BuildEntity do
|
||||
let(:entity) do
|
||||
described_class.new(build, request: double)
|
||||
end
|
||||
|
||||
subject { entity.as_json }
|
||||
|
||||
context 'when build is a regular job' do
|
||||
let(:build) { create(:ci_build) }
|
||||
|
||||
it 'contains url to build page and retry action' do
|
||||
expect(subject).to include(:build_url, :retry_url)
|
||||
expect(subject).not_to include(:play_url)
|
||||
end
|
||||
|
||||
it 'does not contain sensitive information' do
|
||||
expect(subject).not_to include(/token/)
|
||||
expect(subject).not_to include(/variables/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when build is a manual action' do
|
||||
let(:build) { create(:ci_build, :manual) }
|
||||
|
||||
it 'contains url to play action' do
|
||||
expect(subject).to include(:play_url)
|
||||
end
|
||||
end
|
||||
end
|
44
spec/serializers/commit_entity_spec.rb
Normal file
44
spec/serializers/commit_entity_spec.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe CommitEntity do
|
||||
let(:entity) do
|
||||
described_class.new(commit, request: request)
|
||||
end
|
||||
|
||||
let(:request) { double('request') }
|
||||
let(:project) { create(:project) }
|
||||
let(:commit) { project.commit }
|
||||
|
||||
subject { entity.as_json }
|
||||
|
||||
before do
|
||||
allow(request).to receive(:project).and_return(project)
|
||||
end
|
||||
|
||||
context 'when commit author is a user' do
|
||||
before do
|
||||
create(:user, email: commit.author_email)
|
||||
end
|
||||
|
||||
it 'contains information about user' do
|
||||
expect(subject.fetch(:author)).not_to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when commit author is not a user' do
|
||||
it 'does not contain author details' do
|
||||
expect(subject.fetch(:author)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
it 'contains commit URL' do
|
||||
expect(subject).to include(:commit_url)
|
||||
end
|
||||
|
||||
it 'needs to receive project in the request' do
|
||||
expect(request).to receive(:project)
|
||||
.and_return(project)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
20
spec/serializers/deployment_entity_spec.rb
Normal file
20
spec/serializers/deployment_entity_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe DeploymentEntity do
|
||||
let(:entity) do
|
||||
described_class.new(deployment, request: double)
|
||||
end
|
||||
|
||||
let(:deployment) { create(:deployment) }
|
||||
|
||||
subject { entity.as_json }
|
||||
|
||||
it 'exposes internal deployment id' do
|
||||
expect(subject).to include(:iid)
|
||||
end
|
||||
|
||||
it 'exposes nested information about branch' do
|
||||
expect(subject[:ref][:name]).to eq 'master'
|
||||
expect(subject[:ref][:ref_url]).not_to be_empty
|
||||
end
|
||||
end
|
18
spec/serializers/entity_request_spec.rb
Normal file
18
spec/serializers/entity_request_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe EntityRequest do
|
||||
subject do
|
||||
described_class.new(user: 'user', project: 'some project')
|
||||
end
|
||||
|
||||
describe 'methods created' do
|
||||
it 'defines accessible attributes' do
|
||||
expect(subject.user).to eq 'user'
|
||||
expect(subject.project).to eq 'some project'
|
||||
end
|
||||
|
||||
it 'raises error when attribute is not defined' do
|
||||
expect { subject.some_method }.to raise_error NoMethodError
|
||||
end
|
||||
end
|
||||
end
|
18
spec/serializers/environment_entity_spec.rb
Normal file
18
spec/serializers/environment_entity_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe EnvironmentEntity do
|
||||
let(:entity) do
|
||||
described_class.new(environment, request: double)
|
||||
end
|
||||
|
||||
let(:environment) { create(:environment) }
|
||||
subject { entity.as_json }
|
||||
|
||||
it 'exposes latest deployment' do
|
||||
expect(subject).to include(:last_deployment)
|
||||
end
|
||||
|
||||
it 'exposes core elements of environment' do
|
||||
expect(subject).to include(:id, :name, :state, :environment_url)
|
||||
end
|
||||
end
|
60
spec/serializers/environment_serializer_spec.rb
Normal file
60
spec/serializers/environment_serializer_spec.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe EnvironmentSerializer do
|
||||
let(:serializer) do
|
||||
described_class
|
||||
.new(user: user, project: project)
|
||||
.represent(resource)
|
||||
end
|
||||
|
||||
let(:json) { serializer.as_json }
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
|
||||
context 'when there is a single object provided' do
|
||||
before do
|
||||
create(:ci_build, :manual, name: 'manual1',
|
||||
pipeline: deployable.pipeline)
|
||||
end
|
||||
|
||||
let(:deployment) do
|
||||
create(:deployment, deployable: deployable,
|
||||
user: user,
|
||||
project: project,
|
||||
sha: project.commit.id)
|
||||
end
|
||||
|
||||
let(:deployable) { create(:ci_build) }
|
||||
let(:resource) { deployment.environment }
|
||||
|
||||
it 'it generates payload for single object' do
|
||||
expect(json).to be_an_instance_of Hash
|
||||
end
|
||||
|
||||
it 'contains important elements of environment' do
|
||||
expect(json)
|
||||
.to include(:name, :external_url, :environment_url, :last_deployment)
|
||||
end
|
||||
|
||||
it 'contains relevant information about last deployment' do
|
||||
last_deployment = json.fetch(:last_deployment)
|
||||
|
||||
expect(last_deployment)
|
||||
.to include(:ref, :user, :commit, :deployable, :manual_actions)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is a collection of objects provided' do
|
||||
let(:project) { create(:empty_project) }
|
||||
let(:resource) { create_list(:environment, 2) }
|
||||
|
||||
it 'contains important elements of environment' do
|
||||
expect(json.first)
|
||||
.to include(:last_deployment, :name, :external_url)
|
||||
end
|
||||
|
||||
it 'generates payload for collection' do
|
||||
expect(json).to be_an_instance_of Array
|
||||
end
|
||||
end
|
||||
end
|
23
spec/serializers/user_entity_spec.rb
Normal file
23
spec/serializers/user_entity_spec.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe UserEntity do
|
||||
let(:entity) { described_class.new(user) }
|
||||
let(:user) { create(:user) }
|
||||
subject { entity.as_json }
|
||||
|
||||
it 'exposes user name and login' do
|
||||
expect(subject).to include(:username, :name)
|
||||
end
|
||||
|
||||
it 'does not expose passwords' do
|
||||
expect(subject).not_to include(/password/)
|
||||
end
|
||||
|
||||
it 'does not expose tokens' do
|
||||
expect(subject).not_to include(/token/)
|
||||
end
|
||||
|
||||
it 'does not expose 2FA OTPs' do
|
||||
expect(subject).not_to include(/otp/)
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue