diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 7bf27dd00..8110bda9c 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -326,4 +326,59 @@ module RepositoriesHelper end max_space end + + def has_branch_detail? + @repository.scm.respond_to? :branch_contains + end + + def insert_branches_detail(html) + return html unless has_branch_detail? + substring = '' + location = html.index(substring).to_i + substring.length + html.insert(location, branches_html) + end + + def branches_html + content_tag(:li) do + content = content_tag(:strong, "#{l(:label_branch)}") + content << " " + content << "#{@repository.identifier}@ " + content << links_to_branches.join(', ').html_safe + end + end + + def links_to_branches + return [] unless has_branch_detail? + branch_groups.map { |name, branches| branches_link(name, branches) } + end + + def branches_link(name, branches) + return branch_link(branches.first) if branches.length == 1 + link = link_to("[#{name}...]", 'javascript:;', class: 'scm-branch-group').html_safe + content_tag(:span, class: 'scm-branch-hide') do + link << content_tag(:span, class: 'scm-branches') do + branches.map { |branch| branch_link(branch) }.join(', ').html_safe + end + end + end + + def branch_link(branch) + link_to(branch, {:controller => 'repositories', + :action => 'show', + :id => @repository.project, + :repository_id => @repository.identifier, + :path => to_path_param(@path), + :rev => branch}).html_safe + end + + def branch_groups + @repository.scm.branch_contains(@rev).group_by do |branch| + branch.downcase + .gsub(/^\d+/, '#####') + .split(/[\-\._]/) + .first + end.sort_by { |name, branches| [branches.length, name] } + end + + end diff --git a/app/views/issues/tabs/_changesets.html.erb b/app/views/issues/tabs/_changesets.html.erb index f869a5da2..6a77e5b85 100644 --- a/app/views/issues/tabs/_changesets.html.erb +++ b/app/views/issues/tabs/_changesets.html.erb @@ -14,6 +14,12 @@ :repository_id => changeset.repository.identifier_param, :path => "", :rev => changeset.identifier) %>) + <% if !Setting.display_under_associated_revisions? && changeset.scmid.present? + @repository = changeset.repository + @rev = changeset.identifier + %> + (<%= l(:label_branches) %>: <%= links_to_branches.join(', ').html_safe %>) + <% end %> <% end %>

diff --git a/app/views/repositories/_changeset.html.erb b/app/views/repositories/_changeset.html.erb index 393e03e56..e996008d6 100644 --- a/app/views/repositories/_changeset.html.erb +++ b/app/views/repositories/_changeset.html.erb @@ -20,6 +20,13 @@ }.join(", ").html_safe %> <% end %> + <% if !Setting.display_under_single_revision? %> +
  • + <%= l(:label_branches) %> + <%= links_to_branches.join(', ').html_safe %> +
  • + <% end %> + <% if @changeset.children.present? %>
  • <%= l(:label_child_revision) %> diff --git a/app/views/settings/_issues.html.erb b/app/views/settings/_issues.html.erb index b4e50d8e3..f85ecc736 100644 --- a/app/views/settings/_issues.html.erb +++ b/app/views/settings/_issues.html.erb @@ -24,7 +24,16 @@

    <%= setting_text_field :gantt_items_limit, :size => 6 %>

    <%= setting_text_field :gantt_months_limit, :size => 6 %>

    +
  • +
    + <%= l(:label_display_revision_branches) %> +
    +

    <%= setting_check_box :display_under_single_revision %>

    + +

    <%= setting_check_box :display_under_associated_revisions %>

    +
    +
    <%= l(:label_parent_task_attributes) %> diff --git a/config/locales/de.yml b/config/locales/de.yml index 80484859d..4953d4a90 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -460,6 +460,7 @@ de: label_board_sticky: Wichtig (immer oben) label_boolean: Boolean label_branch: Zweig + label_branches: Zweige label_browse: Codebrowser label_bulk_edit_selected_issues: Alle ausgewählten Tickets bearbeiten label_bulk_edit_selected_time_entries: Ausgewählte Zeitaufwände bearbeiten @@ -1004,6 +1005,8 @@ de: setting_default_projects_tracker_ids: Standardmäßig aktivierte Tracker für neue Projekte setting_diff_max_lines_displayed: Maximale Anzahl anzuzeigender Diff-Zeilen setting_display_subprojects_issues: Tickets von Unterprojekten im Hauptprojekt anzeigen + setting_display_under_single_revision: Unterschiede bei Revision anzeigen + setting_display_under_associated_revisions: Bei zugehörigen Revisionen anzeigen setting_emails_footer: E-Mail-Fußzeile setting_emails_header: E-Mail-Kopfzeile setting_enabled_scm: Aktivierte Versionskontrollsysteme @@ -1300,6 +1303,7 @@ de: label_ends_with: endet mit label_issue_fixed_version_updated: Zielversion aktualisiert setting_project_list_defaults: Voreinstellungen Projektliste + label_display_revision_branches: Zweige zur Revision anzeigen label_display_type: Ergebnisse anzeigen als label_display_type_list: Liste label_display_type_board: Karte diff --git a/config/locales/en.yml b/config/locales/en.yml index dce5bda76..431b8b532 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -431,6 +431,8 @@ en: setting_time_format: Time format setting_timespan_format: Time span format setting_cross_project_issue_relations: Allow cross-project issue relations + setting_display_under_single_revision: Display revision under Single Revision + setting_display_under_associated_revisions: Display revision under Associated Revisions setting_cross_project_subtasks: Allow cross-project subtasks setting_issue_list_default_columns: Isuses list defaults setting_repositories_encodings: Attachments and repositories encodings @@ -805,6 +807,7 @@ en: label_repository_plural: Repositories label_browse: Browse label_branch: Branch + label_branches: Branches label_tag: Tag label_revision: Revision label_revision_plural: Revisions @@ -932,6 +935,7 @@ en: label_registration_manual_activation: manual account activation label_registration_automatic_activation: automatic account activation label_display_per_page: "Per page: %{value}" + label_display_revision_branches: Show branches for revision label_age: Age label_change_properties: Change properties label_general: General diff --git a/config/settings.yml b/config/settings.yml index 01f55a970..30de4ac1a 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -226,6 +226,10 @@ issue_list_default_columns: issue_list_default_totals: serialized: true default: [] +display_under_single_revision: + default: true +display_under_associated_revisions: + default: true display_subprojects_issues: default: 1 time_entry_list_defaults: diff --git a/lib/redmine/scm/adapters/git_adapter.rb b/lib/redmine/scm/adapters/git_adapter.rb index 192df0229..5ac50f9a3 100644 --- a/lib/redmine/scm/adapters/git_adapter.rb +++ b/lib/redmine/scm/adapters/git_adapter.rb @@ -95,6 +95,19 @@ module Redmine rescue ScmCommandAborted nil end + + def branch_contains(hash) + cleaned_hash = hash.sub(/[^\w]/, '') + cmd_args = ['branch', '--contains', cleaned_hash] + begin + branches = git_cmd(cmd_args) do |io| + io.readlines.sort!.map{|t| t.strip.gsub(/\* ?/, '')} + end + rescue ScmCommandAborted + branches = Array.new + end + branches.uniq + end def tags return @tags if @tags diff --git a/public/javascripts/repository_navigation.js b/public/javascripts/repository_navigation.js index 61f8446e7..44674d761 100644 --- a/public/javascripts/repository_navigation.js +++ b/public/javascripts/repository_navigation.js @@ -33,4 +33,8 @@ $(document).ready(function() { $('#branch,#tag').removeAttr('disabled'); } }); + + $('a.scm-branch-group').on('click', function() { + $(this).parent().removeClass('scm-branch-hide'); + }); }) diff --git a/public/stylesheets/scm.css b/public/stylesheets/scm.css index 4640be5f9..4d42d7085 100644 --- a/public/stylesheets/scm.css +++ b/public/stylesheets/scm.css @@ -120,3 +120,6 @@ div.action_A { background: #bfb } .breadcrumbs>.separator::before, .breadcrumbs>.separator::after { content: " "; } + +.scm-branch-group, .scm-branch-hide > .scm-branches { display: none; } +.scm-branch-hide > .scm-branch-group { display: inline; }