File: git.rb

package info (click to toggle)
ditz 0.5-1
  • links: PTS
  • area: main
  • in suites: squeeze, wheezy
  • size: 356 kB
  • ctags: 489
  • sloc: ruby: 3,664; sh: 15; makefile: 12
file content (153 lines) | stat: -rw-r--r-- 5,203 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
## git ditz plugin
## 
## This plugin allows issues to be associated with git commits and git
## branches.  Git commits can be easily tagged with a ditz issue with the 'ditz
## commit' command, and both 'ditz show' and the ditz HTML output will then
## contain a list of associated commits for each issue.
##
## Issues can also be assigned a single git feature branch. In this case, all
## commits on that branch will listed as commits for that issue. This
## particular feature is fairly rudimentary, however---it assumes the reference
## point is the 'master' branch, and once the feature branch is merged back
## into master, the list of commits disappears.
##
## Two configuration variables are added, which, when specified, are used to
## construct HTML links for the git commit id and branch names in the generated
## HTML output.
##
## Commands added:
##   ditz set-branch: set the git branch of an issue
##   ditz commit: run git-commit, and insert the issue id into the commit
##     message.
##
## Usage: 
##   1. add a line "- git" to the .ditz-plugins file in the project root
##   2. run ditz reconfigure, and enter the URL prefixes, if any, from
##      which to create commit and branch links.
##   3. use 'ditz commit' with abandon.

require 'time'

module Ditz
class Issue
  field :git_branch, :ask => false

  def git_commits
    return @git_commits if @git_commits

    filters = ["--grep=\"Ditz-issue: #{id}\""]
    filters << "master..#{git_branch}" if git_branch

    output = filters.map do |f|
      `git log --pretty=format:\"%aD\t%an <%ae>\t%h\t%s\" #{f}`
    end.join

    @git_commits = output.split(/\n/).map { |l| l.split("\t") }.
      map { |date, email, hash, msg| [Time.parse(date).utc, email, hash, msg] }
  end
end

class Config
  field :git_commit_url_prefix, :prompt => "URL prefix to link git commits to", :default => ""
  field :git_branch_url_prefix, :prompt => "URL prefix to link git branches to", :default => ""
end

class ScreenView
  add_to_view :issue_summary do |issue, config|
    " Git branch: #{issue.git_branch || 'none'}\n"
  end

  add_to_view :issue_details do |issue, config|
    commits = issue.git_commits[0...5]
    next if commits.empty?
    "Recent commits:\n" + commits.map do |date, email, hash, msg|
      "- #{msg} [#{hash}] (#{email.shortened_email}, #{date.ago} ago)\n"
     end.join + "\n"
  end
end

class HtmlView
  add_to_view :issue_summary do |issue, config|
    next unless issue.git_branch
    [<<EOS, { :issue => issue, :url_prefix => config.git_branch_url_prefix }]
<tr>
  <td class='attrname'>Git branch:</td>
  <td class='attrval'><%= url_prefix && !url_prefix.blank? ? link_to([url_prefix, issue.git_branch].join, issue.git_branch) : h(issue.git_branch) %></td>
</tr>
EOS
  end

  add_to_view :issue_details do |issue, config|
    commits = issue.git_commits
    next if commits.empty?

    [<<EOS, { :commits => commits, :url_prefix => config.git_commit_url_prefix }]
<h2>Commits for this issue</h2>
<table class="log">
<% commits.each_with_index do |(time, who, hash, msg), i| %>
  <tr class="<%= i % 2 == 0 ? "even-row" : "odd-row" %>">
  <td class="time"><%=t time %></td>
  <td class="person"><%=obscured_email who %></td>
  <td class="message"><%=h msg %> [<%= url_prefix && !url_prefix.blank? ? link_to([url_prefix, hash].join, hash) : hash %>]</td>
  </tr>
  <tr><td></td></tr>
<% end %>
</table>
EOS
  end
end

class Operator
  operation :set_branch, "Set the git feature branch of an issue", :issue, :maybe_string
  def set_branch project, config, issue, maybe_string
    puts "Issue #{issue.name} currently " + if issue.git_branch
      "assigned to git branch #{issue.git_branch.inspect}."
    else
      "not assigned to any git branch."
    end

    branch = maybe_string || ask("Git feature branch name:")
    return unless branch

    if branch == issue.git_branch
      raise Error, "issue #{issue.name} already assigned to branch #{issue.git_branch.inspect}"
    end

    puts "Assigning to branch #{branch.inspect}."
    issue.git_branch = branch
  end

  operation :commit, "Runs git-commit and auto-fills the issue name in the commit message", :issue do
    opt :all, "commit all changed files", :short => "-a", :default => false
    opt :verbose, "show diff between HEAD and what would be committed", \
      :short => "-v", :default => false
    opt :message, "Use the given <s> as the commit message.", \
      :short => "-m", :type => :string
    opt :edit, "Further edit the message, even if --message is given.", :short => "-e", :default => false
  end

  def commit project, config, opts, issue
    opts[:edit] = true if opts[:message].nil?

    args = {
      :verbose => "--verbose",
      :all => "--all",
      :edit => "--edit",
    }.map { |k, v| opts[k] ? v : "" }.join(" ")

    comment = "# #{issue.name}: #{issue.title}"
    tag = "Ditz-issue: #{issue.id}"
    message = if opts[:message] && !opts[:edit]
      "#{opts[:message]}\n\n#{tag}"
    elsif opts[:message] && opts[:edit]
      "#{opts[:message]}\n\n#{comment}\n#{tag}"
    else
      "#{comment}\n#{tag}"
    end

    message = message.gsub("\"", "\\\"")
    exec "git commit #{args} --message=\"#{message}\""
  end
end

end