Commit 0aa1f53d authored by Marc's avatar Marc Committed by Douwe Maan

Add signature verification badge to compare view

parent d840535c
...@@ -7,12 +7,12 @@ import { __ } from '~/locale'; ...@@ -7,12 +7,12 @@ import { __ } from '~/locale';
export default class GpgBadges { export default class GpgBadges {
static fetch() { static fetch() {
const badges = $('.js-loading-gpg-badge'); const badges = $('.js-loading-gpg-badge');
const form = $('.commits-search-form'); const tag = $('.js-signature-container');
badges.html('<i class="fa fa-spinner fa-spin"></i>'); badges.html('<i class="fa fa-spinner fa-spin"></i>');
const params = parseQueryStringIntoObject(form.serialize()); const params = parseQueryStringIntoObject(tag.serialize());
return axios.get(form.data('signaturesPath'), { params }) return axios.get(tag.data('signaturesPath'), { params })
.then(({ data }) => { .then(({ data }) => {
data.signatures.forEach((signature) => { data.signatures.forEach((signature) => {
badges.filter(`[data-commit-sha="${signature.commit_sha}"]`).replaceWith(signature.html); badges.filter(`[data-commit-sha="${signature.commit_sha}"]`).replaceWith(signature.html);
......
import Diff from '~/diff'; import Diff from '~/diff';
import initChangesDropdown from '~/init_changes_dropdown'; import initChangesDropdown from '~/init_changes_dropdown';
import GpgBadges from '~/gpg_badges';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
new Diff(); // eslint-disable-line no-new new Diff(); // eslint-disable-line no-new
const paddingTop = 16; const paddingTop = 16;
initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - paddingTop); initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - paddingTop);
GpgBadges.fetch();
}); });
...@@ -8,8 +8,11 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -8,8 +8,11 @@ class Projects::CompareController < Projects::ApplicationController
# Authorize # Authorize
before_action :require_non_empty_project before_action :require_non_empty_project
before_action :authorize_download_code! before_action :authorize_download_code!
before_action :define_ref_vars, only: [:index, :show, :diff_for_path] # Defining ivars
before_action :define_diff_vars, only: [:show, :diff_for_path] before_action :define_diffs, only: [:show, :diff_for_path]
before_action :define_environment, only: [:show]
before_action :define_diff_notes_disabled, only: [:show, :diff_for_path]
before_action :define_commits, only: [:show, :diff_for_path, :signatures]
before_action :merge_request, only: [:index, :show] before_action :merge_request, only: [:index, :show]
def index def index
...@@ -22,9 +25,9 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -22,9 +25,9 @@ class Projects::CompareController < Projects::ApplicationController
end end
def diff_for_path def diff_for_path
return render_404 unless @compare return render_404 unless compare
render_diff_for_path(@compare.diffs(diff_options)) render_diff_for_path(compare.diffs(diff_options))
end end
def create def create
...@@ -41,30 +44,60 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -41,30 +44,60 @@ class Projects::CompareController < Projects::ApplicationController
end end
end end
def signatures
respond_to do |format|
format.json do
render json: {
signatures: @commits.select(&:has_signature?).map do |commit|
{
commit_sha: commit.sha,
html: view_to_html_string('projects/commit/_signature', signature: commit.signature)
}
end
}
end
end
end
private private
def define_ref_vars def compare
@start_ref = Addressable::URI.unescape(params[:from]) return @compare if defined?(@compare)
@compare = CompareService.new(@project, head_ref).execute(@project, start_ref)
end
def start_ref
@start_ref ||= Addressable::URI.unescape(params[:from])
end
def head_ref
return @ref if defined?(@ref)
@ref = @head_ref = Addressable::URI.unescape(params[:to]) @ref = @head_ref = Addressable::URI.unescape(params[:to])
end end
def define_diff_vars def define_commits
@compare = CompareService.new(@project, @head_ref) @commits = compare.present? ? prepare_commits_for_rendering(compare.commits) : []
.execute(@project, @start_ref) end
if @compare def define_diffs
@commits = prepare_commits_for_rendering(@compare.commits) @diffs = compare.present? ? compare.diffs(diff_options) : []
@diffs = @compare.diffs(diff_options) end
environment_params = @repository.branch_exists?(@head_ref) ? { ref: @head_ref } : { commit: @compare.commit } def define_environment
if compare
environment_params = @repository.branch_exists?(head_ref) ? { ref: head_ref } : { commit: compare.commit }
@environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last @environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
@diff_notes_disabled = true
end end
end end
def define_diff_notes_disabled
@diff_notes_disabled = compare.present?
end
def merge_request def merge_request
@merge_request ||= MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened @merge_request ||= MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened
.find_by(source_project: @project, source_branch: @head_ref, target_branch: @start_ref) .find_by(source_project: @project, source_branch: head_ref, target_branch: start_ref)
end end
end end
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
= link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
.control .control
= form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do = form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path }) do
= search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false } = search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
.control .control
= link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
......
= form_tag project_compare_index_path(@project), method: :post, class: 'form-inline js-requires-input' do = form_tag project_compare_index_path(@project), method: :post, class: 'form-inline js-requires-input js-signature-container', data: { 'signatures-path' => signatures_namespace_project_compare_index_path } do
.clearfix .clearfix
- if params[:to] && params[:from] - if params[:to] && params[:from]
.compare-switch-container .compare-switch-container
......
---
title: Add the signature verfication badge to the compare view
merge_request: 18245
author: Marc Shaw
type: added
...@@ -18,6 +18,7 @@ scope format: false do ...@@ -18,6 +18,7 @@ scope format: false do
resources :compare, only: [:index, :create] do resources :compare, only: [:index, :create] do
collection do collection do
get :diff_for_path get :diff_for_path
get :signatures
end end
end end
......
...@@ -3,96 +3,99 @@ require 'spec_helper' ...@@ -3,96 +3,99 @@ require 'spec_helper'
describe Projects::CompareController do describe Projects::CompareController do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:ref_from) { "improve%2Fawesome" }
let(:ref_to) { "feature" }
before do before do
sign_in(user) sign_in(user)
project.add_master(user) project.add_master(user)
end end
it 'compare shows some diffs' do describe 'GET index' do
get(:show, render_views
namespace_id: project.namespace,
project_id: project, before do
from: ref_from, get :index, namespace_id: project.namespace, project_id: project
to: ref_to) end
expect(response).to be_success it 'returns successfully' do
expect(assigns(:diffs).diff_files.first).not_to be_nil expect(response).to be_success
expect(assigns(:commits).length).to be >= 1 end
end end
it 'compare shows some diffs with ignore whitespace change option' do describe 'GET show' do
get(:show, render_views
subject(:show_request) { get :show, request_params }
let(:request_params) do
{
namespace_id: project.namespace, namespace_id: project.namespace,
project_id: project, project_id: project,
from: '08f22f25', from: source_ref,
to: '66eceea0', to: target_ref,
w: 1) w: whitespace
}
expect(response).to be_success end
diff_file = assigns(:diffs).diff_files.first
expect(diff_file).not_to be_nil
expect(assigns(:commits).length).to be >= 1
# without whitespace option, there are more than 2 diff_splits
diff_splits = diff_file.diff.diff.split("\n")
expect(diff_splits.length).to be <= 2
end
describe 'non-existent refs' do let(:whitespace) { nil }
it 'uses invalid source ref' do
get(:show,
namespace_id: project.namespace,
project_id: project,
from: 'non-existent',
to: ref_to)
expect(response).to be_success context 'when the refs exist' do
expect(assigns(:diffs).diff_files.to_a).to eq([]) context 'when we set the white space param' do
expect(assigns(:commits)).to eq([]) let(:source_ref) { "08f22f25" }
end let(:target_ref) { "66eceea0" }
let(:whitespace) { 1 }
it 'uses invalid target ref' do it 'shows some diffs with ignore whitespace change option' do
get(:show, show_request
namespace_id: project.namespace,
project_id: project,
from: ref_from,
to: 'non-existent')
expect(response).to be_success expect(response).to be_success
expect(assigns(:diffs)).to eq(nil) diff_file = assigns(:diffs).diff_files.first
expect(assigns(:commits)).to eq(nil) expect(diff_file).not_to be_nil
end expect(assigns(:commits).length).to be >= 1
# without whitespace option, there are more than 2 diff_splits
diff_splits = diff_file.diff.diff.split("\n")
expect(diff_splits.length).to be <= 2
end
end
context 'when we do not set the white space param' do
let(:source_ref) { "improve%2Fawesome" }
let(:target_ref) { "feature" }
let(:whitespace) { nil }
it 'redirects back to index when params[:from] is empty and preserves params[:to]' do it 'sets the diffs and commits ivars' do
post(:create, show_request
namespace_id: project.namespace,
project_id: project,
from: '',
to: 'master')
expect(response).to redirect_to(project_compare_index_path(project, to: 'master')) expect(response).to be_success
expect(assigns(:diffs).diff_files.first).not_to be_nil
expect(assigns(:commits).length).to be >= 1
end
end
end end
it 'redirects back to index when params[:to] is empty and preserves params[:from]' do context 'when the source ref does not exist' do
post(:create, let(:source_ref) { 'non-existent-source-ref' }
namespace_id: project.namespace, let(:target_ref) { "feature" }
project_id: project,
from: 'master', it 'sets empty diff and commit ivars' do
to: '') show_request
expect(response).to redirect_to(project_compare_index_path(project, from: 'master')) expect(response).to be_success
expect(assigns(:diffs).diff_files.to_a).to eq([])
expect(assigns(:commits)).to eq([])
end
end end
it 'redirects back to index when params[:from] and params[:to] are empty' do context 'when the target ref does not exist' do
post(:create, let(:target_ref) { 'non-existent-target-ref' }
namespace_id: project.namespace, let(:source_ref) { "improve%2Fawesome" }
project_id: project,
from: '',
to: '')
expect(response).to redirect_to(namespace_project_compare_index_path) it 'sets empty diff and commit ivars' do
show_request
expect(response).to be_success
expect(assigns(:diffs)).to eq([])
expect(assigns(:commits)).to eq([])
end
end end
end end
...@@ -107,12 +110,14 @@ describe Projects::CompareController do ...@@ -107,12 +110,14 @@ describe Projects::CompareController do
end end
let(:existing_path) { 'files/ruby/feature.rb' } let(:existing_path) { 'files/ruby/feature.rb' }
let(:source_ref) { "improve%2Fawesome" }
let(:target_ref) { "feature" }
context 'when the from and to refs exist' do context 'when the source and target refs exist' do
context 'when the user has access to the project' do context 'when the user has access target the project' do
context 'when the path exists in the diff' do context 'when the path exists in the diff' do
it 'disables diff notes' do it 'disables diff notes' do
diff_for_path(from: ref_from, to: ref_to, old_path: existing_path, new_path: existing_path) diff_for_path(from: source_ref, to: target_ref, old_path: existing_path, new_path: existing_path)
expect(assigns(:diff_notes_disabled)).to be_truthy expect(assigns(:diff_notes_disabled)).to be_truthy
end end
...@@ -123,13 +128,13 @@ describe Projects::CompareController do ...@@ -123,13 +128,13 @@ describe Projects::CompareController do
meth.call(diffs) meth.call(diffs)
end end
diff_for_path(from: ref_from, to: ref_to, old_path: existing_path, new_path: existing_path) diff_for_path(from: source_ref, to: target_ref, old_path: existing_path, new_path: existing_path)
end end
end end
context 'when the path does not exist in the diff' do context 'when the path does not exist in the diff' do
before do before do
diff_for_path(from: ref_from, to: ref_to, old_path: existing_path.succ, new_path: existing_path.succ) diff_for_path(from: source_ref, to: target_ref, old_path: existing_path.succ, new_path: existing_path.succ)
end end
it 'returns a 404' do it 'returns a 404' do
...@@ -138,10 +143,10 @@ describe Projects::CompareController do ...@@ -138,10 +143,10 @@ describe Projects::CompareController do
end end
end end
context 'when the user does not have access to the project' do context 'when the user does not have access target the project' do
before do before do
project.team.truncate project.team.truncate
diff_for_path(from: ref_from, to: ref_to, old_path: existing_path, new_path: existing_path) diff_for_path(from: source_ref, to: target_ref, old_path: existing_path, new_path: existing_path)
end end
it 'returns a 404' do it 'returns a 404' do
...@@ -150,9 +155,9 @@ describe Projects::CompareController do ...@@ -150,9 +155,9 @@ describe Projects::CompareController do
end end
end end
context 'when the from ref does not exist' do context 'when the source ref does not exist' do
before do before do
diff_for_path(from: ref_from.succ, to: ref_to, old_path: existing_path, new_path: existing_path) diff_for_path(from: source_ref.succ, to: target_ref, old_path: existing_path, new_path: existing_path)
end end
it 'returns a 404' do it 'returns a 404' do
...@@ -160,9 +165,9 @@ describe Projects::CompareController do ...@@ -160,9 +165,9 @@ describe Projects::CompareController do
end end
end end
context 'when the to ref does not exist' do context 'when the target ref does not exist' do
before do before do
diff_for_path(from: ref_from, to: ref_to.succ, old_path: existing_path, new_path: existing_path) diff_for_path(from: source_ref, to: target_ref.succ, old_path: existing_path, new_path: existing_path)
end end
it 'returns a 404' do it 'returns a 404' do
...@@ -170,4 +175,153 @@ describe Projects::CompareController do ...@@ -170,4 +175,153 @@ describe Projects::CompareController do
end end
end end
end end
describe 'POST create' do
subject(:create_request) { post :create, request_params }
let(:request_params) do
{
namespace_id: project.namespace,
project_id: project,
from: source_ref,
to: target_ref
}
end
context 'when sending valid params' do
let(:source_ref) { "improve%2Fawesome" }
let(:target_ref) { "feature" }
it 'redirects back to show' do
create_request
expect(response).to redirect_to(project_compare_path(project, to: target_ref, from: source_ref))
end
end
context 'when sending invalid params' do
context 'when the source ref is empty and target ref is set' do
let(:source_ref) { '' }
let(:target_ref) { 'master' }
it 'redirects back to index and preserves the target ref' do
create_request
expect(response).to redirect_to(project_compare_index_path(project, to: target_ref))
end
end
context 'when the target ref is empty and source ref is set' do
let(:source_ref) { 'master' }
let(:target_ref) { '' }
it 'redirects back to index and preserves source ref' do
create_request
expect(response).to redirect_to(project_compare_index_path(project, from: source_ref))
end
end
context 'when the target and source ref are empty' do
let(:source_ref) { '' }
let(:target_ref) { '' }
it 'redirects back to index' do
create_request
expect(response).to redirect_to(namespace_project_compare_index_path)
end
end
end
end
describe 'GET signatures' do
subject(:signatures_request) { get :signatures, request_params }
let(:request_params) do
{
namespace_id: project.namespace,
project_id: project,
from: source_ref,
to: target_ref,
format: :json
}
end
context 'when the source and target refs exist' do
let(:source_ref) { "improve%2Fawesome" }
let(:target_ref) { "feature" }
context 'when the user has access to the project' do
render_views
let(:signature_commit) { build(:commit, project: project, safe_message: "message", sha: 'signature_commit') }
let(:non_signature_commit) { build(:commit, project: project, safe_message: "message", sha: 'non_signature_commit') }
before do
escaped_source_ref = Addressable::URI.unescape(source_ref)
escaped_target_ref = Addressable::URI.unescape(target_ref)
compare_service = CompareService.new(project, escaped_target_ref)
compare = compare_service.execute(project, escaped_source_ref)
expect(CompareService).to receive(:new).with(project, escaped_target_ref).and_return(compare_service)
expect(compare_service).to receive(:execute).with(project, escaped_source_ref).and_return(compare)
expect(compare).to receive(:commits).and_return([signature_commit, non_signature_commit])
expect(non_signature_commit).to receive(:has_signature?).and_return(false)
end
it 'returns only the commit with a signature' do
signatures_request
expect(response).to have_gitlab_http_status(200)
parsed_body = JSON.parse(response.body)
signatures = parsed_body['signatures']
expect(signatures.size).to eq(1)
expect(signatures.first['commit_sha']).to eq(signature_commit.sha)
expect(signatures.first['html']).to be_present
end
end
context 'when the user does not have access to the project' do
before do
project.team.truncate
end
it 'returns a 404' do
signatures_request
expect(response).to have_gitlab_http_status(404)
end
end
end
context 'when the source ref does not exist' do
let(:source_ref) { 'non-existent-ref-source' }
let(:target_ref) { "feature" }
it 'returns no signatures' do
signatures_request
expect(response).to have_gitlab_http_status(200)
parsed_body = JSON.parse(response.body)
expect(parsed_body['signatures']).to be_empty
end
end
context 'when the target ref does not exist' do
let(:target_ref) { 'non-existent-ref-target' }
let(:source_ref) { "improve%2Fawesome" }
it 'returns no signatures' do
signatures_request
expect(response).to have_gitlab_http_status(200)
parsed_body = JSON.parse(response.body)
expect(parsed_body['signatures']).to be_empty
end
end
end
end end
...@@ -16,8 +16,8 @@ describe('GpgBadges', () => { ...@@ -16,8 +16,8 @@ describe('GpgBadges', () => {
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
setFixtures(` setFixtures(`
<form <form
class="commits-search-form" data-signatures-path="/hello" action="/hello" class="commits-search-form js-signature-container" data-signatures-path="/hello" action="/hello"
method="get"> method="get">
<input name="utf8" type="hidden" value="✓"> <input name="utf8" type="hidden" value="✓">
<input type="search" name="search" id="commits-search"class="form-control search-text-input input-short"> <input type="search" name="search" id="commits-search"class="form-control search-text-input input-short">
......
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