Read about our upcoming Code of Conduct on this issue

Commit 27f2ca94 authored by Douwe Maan's avatar Douwe Maan
Browse files

Add 'View on [env]' link to blobs and individual files in diffs

parent 0007b97be271
......@@ -30,6 +30,9 @@ def create
end
def show
branch_name = @ref if @repository.branch_exists?(@ref)
@environment = @project.latest_environment_for(@commit, ref: branch_name)
@environment = nil unless can?(current_user, :read_environment, @environment)
end
def edit
......
......@@ -95,6 +95,9 @@ def define_commit_vars
@diffs = commit.diffs(opts)
@notes_count = commit.notes.count
@environment = @project.latest_environment_for(@commit)
@environment = nil unless can?(current_user, :read_environment, @environment)
end
def define_note_vars
......
......@@ -57,6 +57,10 @@ def define_diff_vars
@diffs = @compare.diffs(diff_options)
branch_name = @head_ref if @repository.branch_exists?(@head_ref)
@environment = @project.latest_environment_for(@commit, ref: branch_name)
@environment = nil unless can?(current_user, :read_environment, @environment)
@diff_notes_disabled = true
@grouped_diff_discussions = {}
end
......
......@@ -103,6 +103,9 @@ def diffs
end
end
@environment = @merge_request.latest_environment
@environment = nil unless can?(current_user, :read_environment, @environment)
respond_to do |format|
format.html { define_discussion_vars }
format.json do
......@@ -245,7 +248,10 @@ def new_diffs
end
@diff_notes_disabled = true
render json: { html: view_to_html_string('projects/merge_requests/_new_diffs', diffs: @diffs) }
@environment = @merge_request.latest_environment
@environment = nil unless can?(current_user, :read_environment, @environment)
render json: { html: view_to_html_string('projects/merge_requests/_new_diffs', diffs: @diffs, environment: @environment) }
end
end
end
......
......@@ -205,6 +205,17 @@ def view_file_btn(commit_sha, diff_new_path, project)
end
end
def view_on_environment_btn(commit_sha, diff_new_path, environment)
return unless environment && commit_sha
external_url = environment.external_url_for(diff_new_path, commit_sha)
return unless external_url
link_to(external_url, class: 'btn btn-file-option has-tooltip', target: '_blank', title: "View on #{environment.formatted_external_url}", data: { container: 'body' }) do
icon('external-link')
end
end
def truncate_sha(sha)
Commit.truncate_sha(sha)
end
......
......@@ -283,13 +283,7 @@ def config_processor
def ci_yaml_file
return @ci_yaml_file if defined?(@ci_yaml_file)
@ci_yaml_file ||= begin
blob = project.repository.blob_at(sha, '.gitlab-ci.yml')
blob.load_all_data!(project.repository)
blob.data
rescue
nil
end
@ci_yaml_file ||= project.repository.ci_yaml_file(sha)
end
def has_yaml_errors?
......
......@@ -51,6 +51,14 @@ class Environment < ActiveRecord::Base
state :stopped
end
def self.latest_for_commit(environments, commit)
environments.sort_by do |environment|
deployment = environment.first_deployment_for(commit)
deployment.try(:created_at) || DateTime.parse('1970-01-01')
end.last
end
def predefined_variables
[
{ key: 'CI_ENVIRONMENT_NAME', value: name, public: true },
......@@ -171,6 +179,16 @@ def generate_slug
self.slug = slugified
end
def external_url_for(path, commit_sha)
return unless self.external_url
public_path = project.public_path_for_source_path(path, commit_sha)
return unless public_path
# TODO: Verify this can't be used for XSS
URI.join(external_url, public_path).to_s
end
private
# Slugifying a name may remove the uniqueness guarantee afforded by it being
......
......@@ -729,6 +729,12 @@ def environments
end
end
def latest_environment
return @latest_environment if defined?(@latest_environment)
@latest_environment = Environment.latest_for_commit(environments, diff_head_commit)
end
def state_human_name
if merged?
"Merged"
......
......@@ -1307,10 +1307,17 @@ def reset_pushes_since_gc
end
def environments_for(ref, commit: nil, with_tags: false)
deployments_query = with_tags ? 'ref = ? OR tag IS TRUE' : 'ref = ?'
deps =
if ref
deployments_query = with_tags ? 'ref = ? OR tag IS TRUE' : 'ref = ?'
deployments.where(deployments_query, ref.to_s)
elsif commit
deps = deployments.where(sha: commit.sha)
else
Deployment.none
end
environment_ids = deployments
.where(deployments_query, ref.to_s)
environment_ids = deps
.group(:environment_id)
.select(:environment_id)
......@@ -1324,12 +1331,46 @@ def environments_for(ref, commit: nil, with_tags: false)
end
end
def latest_environment_for(commit, ref: nil)
environments = environments_for(ref, commit: commit)
Environment.latest_for_commit(environments, commit)
end
def environments_recently_updated_on_branch(branch)
environments_for(branch).select do |environment|
environment.recently_updated_on_branch?(branch)
end
end
def route_map_for_commit(commit_sha)
@route_maps_by_commit ||= Hash.new do |h, sha|
h[sha] = begin
data = repository.route_map_file(sha)
next unless data
# TODO: Validate
YAML.safe_load(data).map do |mapping|
{
source: Regexp.new("^#{mapping['source'][1...-1]}$"),
public: mapping['public']
}
end
end
end
@route_maps_by_commit[commit_sha]
end
def public_path_for_source_path(path, commit_sha)
map = route_map_for_commit(commit_sha)
return unless map
mapping = map.find { |mapping| path =~ mapping[:source] }
return unless mapping
path.sub(mapping[:source], mapping[:public])
end
private
def cross_namespace_reference?(from)
......
......@@ -35,6 +35,9 @@ class Repository
avatar: :avatar
}
ROUTE_MAP_PATH = '.gitlab/route-map.yml'
GITLAB_CI_YML_PATH = '.gitlab-ci.yml'
# Wraps around the given method and caches its output in Redis and an instance
# variable.
#
......@@ -1184,6 +1187,20 @@ def check_tree_entry_for_dir(branch_name, path)
end
end
def route_map_file(sha)
blob = blob_at(sha, ROUTE_MAP_PATH)
return unless blob
blob.load_all_data!(self)
blob.data
end
def ci_yaml_file(sha)
blob = blob_at(sha, GITLAB_CI_YML_PATH)
return unless blob
blob.load_all_data!(self)
blob.data
end
private
def git_action(index, action)
......
.btn-group
= view_on_environment_btn(@commit.sha, @path, @environment) if @environment
.btn-group.tree-btn-group
= link_to 'Raw', namespace_project_raw_path(@project.namespace, @project, @id),
class: 'btn btn-sm', target: '_blank'
......
......@@ -9,7 +9,7 @@
= render "ci_menu"
- else
.block-connector
= render "projects/diffs/diffs", diffs: @diffs
= render "projects/diffs/diffs", diffs: @diffs, environment: @environment
= render "projects/notes/notes_with_form"
- if can_collaborate_with_project?
- %w(revert cherry-pick).each do |type|
......
......@@ -8,7 +8,7 @@
- if @commits.present?
= render "projects/commits/commit_list"
= render "projects/diffs/diffs", diffs: @diffs
= render "projects/diffs/diffs", diffs: @diffs, environment: @environment
- else
.light-well
.center
......
- environment = local_assigns.fetch(:environment, nil)
- show_whitespace_toggle = local_assigns.fetch(:show_whitespace_toggle, true)
- can_create_note = !@diff_notes_disabled && can?(current_user, :create_note, diffs.project)
- diff_files = diffs.diff_files
......@@ -30,4 +31,4 @@
- file_hash = hexdigest(diff_file.file_path)
= render 'projects/diffs/file', file_hash: file_hash, project: diffs.project,
diff_file: diff_file, diff_commit: diff_commit, blob: blob
diff_file: diff_file, diff_commit: diff_commit, blob: blob, environment: environment
- environment = local_assigns.fetch(:environment, nil)
.diff-file.file-holder{ id: file_hash, data: diff_file_html_data(project, diff_file.file_path, diff_commit.id) }
.file-title
= render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_commit, project: project, url: "##{file_hash}"
......@@ -14,5 +15,6 @@
blob: blob, link_opts: link_opts)
= view_file_btn(diff_commit.id, diff_file.new_path, project)
= view_on_environment_btn(diff_commit.id, diff_file.new_path, environment) if environment
= render 'projects/diffs/content', diff_file: diff_file, diff_commit: diff_commit, blob: blob, project: project
= render "projects/diffs/diffs", diffs: @diffs, show_whitespace_toggle: false
= render "projects/diffs/diffs", diffs: @diffs, environment: @environment, show_whitespace_toggle: false
- if @merge_request_diff.collected? || @merge_request_diff.overflow?
= render 'projects/merge_requests/show/versions'
= render "projects/diffs/diffs", diffs: @diffs
= render "projects/diffs/diffs", diffs: @diffs, environment: @environment
- elsif @merge_request_diff.empty?
.nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
---
title: Add 'View on [env]' link to blobs and individual files in diffs
merge_request:
author:
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