Project

General

Profile

Feature #5386 » 0001-5386-Branch-Tags-in-Changeset-Description-7.patch

Marco Descher, 2026-11-04 08:50

View differences:

app/assets/javascripts/application-legacy.js
1568 1568
$(document).on('focus', '[data-auto-complete=true]', function(event) {
1569 1569
  inlineAutoComplete(event.target);
1570 1570
});
1571

  
1572
// Branch groups are rendered on the revision page and in the issue
1573
// history tab, which is loaded later. Delegation keeps the expander working.
1574
$(document).on('click', 'a.scm-branch-group', function(e) {
1575
  e.preventDefault();
1576
  $(this).parent().removeClass('scm-branch-hide');
1577
});
app/assets/javascripts/repository_navigation.js
36 36
      $('#branch,#tag').removeAttr('disabled');
37 37
    }
38 38
  });
39

  
40
  $('a.scm-branch-group').on('click', function(e) {
41
    e.preventDefault();
42
    $(this).parent().removeClass('scm-branch-hide');
43
  });
39 44
})
app/assets/stylesheets/application.css
2725 2725
#sidebar .api-key-actions .copy-api-key-link svg {
2726 2726
  opacity: 1;
2727 2727
}
2728

  
2729
.scm-branch-group, .scm-branch-hide > .scm-branches { display: none; }
2730
.scm-branch-hide > .scm-branch-group { display: inline; }
app/assets/stylesheets/scm.css
181 181
.breadcrumbs>.separator::before, .breadcrumbs>.separator::after {
182 182
    content: " ";
183 183
}
184

  
185
.scm-branch-group, .scm-branch-hide > .scm-branches { display: none; }
186
.scm-branch-hide > .scm-branch-group { display: inline; }
app/helpers/repositories_helper.rb
339 339
    end
340 340
    max_space
341 341
  end
342

  
343
  def has_branch_detail?(repository = @repository)
344
    repository.present? && repository.scm.respond_to?(:branch_contains)
345
  rescue Redmine::Scm::Adapters::CommandFailed
346
    false
347
  end
348

  
349
  def insert_branches_detail(html)
350
    return html unless has_branch_detail?
351

  
352
    html = html.to_s.dup
353
    substring = '</li>'
354
    index = html.index(substring)
355
    return html.html_safe unless index
356

  
357
    html.insert(index + substring.length, branches_html)
358
    html.html_safe
359
  end
360

  
361
  def branches_html
362
    content_tag(:li) do
363
      safe_join(
364
        [
365
          content_tag(:strong, l(:label_branch)),
366
          ' ',
367
          "#{@repository.identifier}@ ",
368
          safe_join(links_to_branches, ', ')
369
        ]
370
      )
371
    end
372
  end
373

  
374
  def links_to_branches(repository = @repository, rev = @rev)
375
    return [] unless has_branch_detail?(repository)
376

  
377
    branch_groups(repository, rev).map do |name, branches|
378
      branches_link(repository, name, branches)
379
    end
380
  rescue Redmine::Scm::Adapters::CommandFailed
381
    []
382
  end
383

  
384
  def branches_link(repository, name, branches)
385
    return branch_link(repository, branches.first) if branches.length == 1
386

  
387
    link = link_to("[#{name}...]", 'javascript:;', :class => 'scm-branch-group')
388
    content_tag(:span, :class => 'scm-branch-hide') do
389
      link + content_tag(
390
        :span,
391
        safe_join(branches.map {|branch| branch_link(repository, branch)}, ', '),
392
        :class => 'scm-branches'
393
      )
394
    end
395
  end
396

  
397
  def branch_link(repository, branch)
398
    link_to(
399
      branch,
400
      {
401
        :controller => 'repositories',
402
        :action => 'show',
403
        :id => repository.project,
404
        :repository_id => repository.identifier_param,
405
        :path => to_path_param(@path),
406
        :rev => branch
407
      }
408
    )
409
  end
410

  
411
  def branch_groups(repository = @repository, rev = @rev)
412
    return [] if rev.blank?
413

  
414
    repository.scm.branch_contains(rev).group_by do |branch|
415
      branch.downcase.gsub(/^\d+/, '#####').split(/[\-\._]/).first
416
    end.sort_by {|name, branches| [branches.length, name.to_s]}
417
  end
342 418
end
app/views/issues/tabs/_changesets.html.erb
20 20
                       :path => "",
21 21
                       :rev => changeset.identifier) %>)
22 22
        <% end %>
23
        <% if Setting.display_under_associated_revisions? && changeset.scmid.present? &&
24
              has_branch_detail?(changeset.repository) %>
25
          <% branch_links = links_to_branches(changeset.repository, changeset.identifier) %>
26
          <% if branch_links.any? %>
27
            (<em><%= l(:label_branches) %>: <%= safe_join(branch_links, ', ') %></em>)
28
          <% end %>
29
        <% end %>
23 30
      </p>
24 31
      <div class="wiki changeset-comments">
25 32
        <%= format_changeset_comments changeset %>
app/views/repositories/_changeset.html.erb
5 5
    <%= avatar(@changeset.user) %>
6 6
    <%= authoring(@changeset.committed_on, @changeset.author) %>
7 7
  </h4>
8
  <% if @changeset.scmid.present? || @changeset.parents.present? || @changeset.children.present? %>
8
  <% branch_links =
9
       if Setting.display_under_single_revision? && has_branch_detail?
10
         links_to_branches(@repository, @changeset.scmid.presence || @rev)
11
       else
12
         []
13
       end %>
14
  <% if @changeset.scmid.present? || @changeset.parents.present? || @changeset.children.present? || branch_links.any? %>
9 15
  <ul class="revision-info">
10 16
    <% if @changeset.scmid.present? %>
11 17
      <li>
......
20 26
              }.join(", ").html_safe %>
21 27
      </li>
22 28
    <% end %>
29
    <% if branch_links.any? %>
30
      <li>
31
        <strong><%= l(:label_branches) %></strong>
32
        <%= safe_join(branch_links, ', ') %>
33
      </li>
34
    <% end %>
23 35
    <% if @changeset.children.present? %>
24 36
      <li>
25 37
        <strong><%= l(:label_child_revision) %></strong>
app/views/settings/_issues.html.erb
59 59
<p><%= setting_text_field :gantt_months_limit, :size => 6 %></p>
60 60
</div>
61 61

  
62
<fieldset class="box">
63
  <legend><%= l(:label_display_revision_branches) %></legend>
64
  <div class="tabular settings">
65
    <p><%= setting_check_box :display_under_single_revision %></p>
66

  
67
    <p><%= setting_check_box :display_under_associated_revisions %></p>
68
  </div>
69
</fieldset>
70

  
62 71
<fieldset class="box">
63 72
  <legend><%= l(:label_parent_task_attributes) %></legend>
64 73
  <div class="tabular settings">
config/locales/de.yml
462 462
  label_board_sticky: Wichtig (immer oben)
463 463
  label_boolean: Boolean
464 464
  label_branch: Zweig
465
  label_branches: Zweige
465 466
  label_bulk_edit_selected_issues: Alle ausgewählten Tickets bearbeiten
466 467
  label_bulk_edit_selected_time_entries: Ausgewählte Zeitaufwände bearbeiten
467 468
  label_calendar: Kalender
......
1010 1011
  setting_default_projects_tracker_ids: Standardmäßig aktivierte Tracker für neue Projekte
1011 1012
  setting_diff_max_lines_displayed: Maximale Anzahl anzuzeigender Diff-Zeilen
1012 1013
  setting_display_subprojects_issues: Tickets von Unterprojekten im Hauptprojekt anzeigen
1014
  setting_display_under_single_revision: Unterschiede bei Revision anzeigen
1015
  setting_display_under_associated_revisions: Bei zugehörigen Revisionen anzeigen
1013 1016
  setting_emails_footer: E-Mail-Fußzeile
1014 1017
  setting_emails_header: E-Mail-Kopfzeile
1015 1018
  setting_enabled_scm: Aktivierte Versionskontrollsysteme
......
1305 1308
  label_ends_with: endet mit
1306 1309
  label_issue_fixed_version_updated: Zielversion aktualisiert
1307 1310
  setting_project_list_defaults: Voreinstellungen Projektliste
1311
  label_display_revision_branches: Zweige zur Revision anzeigen
1308 1312
  label_display_type: Ergebnisse anzeigen als
1309 1313
  label_display_type_list: Liste
1310 1314
  label_display_type_board: Karte
config/locales/en.yml
456 456
  setting_time_format: Time format
457 457
  setting_timespan_format: Time span format
458 458
  setting_cross_project_issue_relations: Allow cross-project issue relations
459
  setting_display_under_single_revision: Display revision under Single Revision
460
  setting_display_under_associated_revisions: Display revision under Associated Revisions
459 461
  setting_cross_project_subtasks: Allow cross-project subtasks
460 462
  setting_issue_list_default_columns: Issues list defaults
461 463
  setting_repositories_encodings: Attachments and repositories encodings
......
855 857
  label_repository_new: New repository
856 858
  label_repository_plural: Repositories
857 859
  label_branch: Branch
860
  label_branches: Branches
858 861
  label_tag: Tag
859 862
  label_revision: Revision
860 863
  label_revision_plural: Revisions
......
979 982
  label_registration_manual_activation: Account activation by administrator approval
980 983
  label_registration_automatic_activation: Automatic account activation
981 984
  label_display_per_page: "Per page: %{value}"
985
  label_display_revision_branches: Show branches for revision
982 986
  label_age: Age
983 987
  label_change_properties: Change properties
984 988
  label_general: General
config/settings.yml
245 245
  - done_ratio
246 246
display_related_issues_table_headers:
247 247
  default: 0
248
display_under_single_revision:
249
  default: 1
250
display_under_associated_revisions:
251
  default: 1
248 252
display_subprojects_issues:
249 253
  default: 1
250 254
time_entry_list_defaults:
lib/redmine/scm/adapters/git_adapter.rb
94 94
          nil
95 95
        end
96 96

  
97
        # Local branch names that contain the given commit.
98
        # Non-word characters are stripped before the value is passed to git.
99
        def branch_contains(hash)
100
          cleaned_hash = hash.to_s.gsub(/[^\w]/, '')
101
          return [] if cleaned_hash.empty?
102

  
103
          cmd_args = %w|branch --no-color --contains|
104
          cmd_args << cleaned_hash
105
          branches = []
106
          git_cmd(cmd_args) do |io|
107
            branches =
108
              io.readlines.filter_map do |line|
109
                name = line.strip.sub(/\A[*+]\s*/, '')
110
                next if name.empty?
111

  
112
                scm_iconv('UTF-8', @path_encoding, name)
113
              end
114
          end
115
          branches.sort.uniq
116
        rescue ScmCommandAborted
117
          []
118
        end
119

  
97 120
        def tags
98 121
          return @tags if @tags
99 122

  
(12-12/12)