ditz-str 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +24 -0
- data/LICENSE +674 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/README.txt +143 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/bin/ditz-str +189 -0
- data/bugs/issue-02615b8c3dd0382c92f350ce2158ecfe94d11ef8.yaml +22 -0
- data/bugs/issue-06a3bbf35a60c4da2d8ea0fdc86164263126d6b2.yaml +22 -0
- data/bugs/issue-0c00c1d7fdffaad304e62d79d9b3d5e92547055b.yaml +38 -0
- data/bugs/issue-20dad4b4533d6d76d496fe5970098f1eb8efd561.yaml +26 -0
- data/bugs/issue-360ae6529dbc66358fde6b532cbea79ece37a670.yaml +22 -0
- data/bugs/issue-5177d61bf3c2783f71ef63e6e2c5e720247ef699.yaml +18 -0
- data/bugs/issue-695b564c210da1965a2bb38eef782178aead6952.yaml +26 -0
- data/bugs/issue-7d0ce6429a9fb5fa09ce3376a8921a5ecb7ecfe5.yaml +34 -0
- data/bugs/issue-a04462fa22ab6e1b02cfdd052d1f6c6f491f08f5.yaml +22 -0
- data/bugs/issue-bca54ca5107eabc3b281701041cc36ea0641cbdd.yaml +26 -0
- data/bugs/issue-d0c7d04b014d705c5fd865e4d487b5e5b6983c33.yaml +26 -0
- data/bugs/issue-f94b879842aa0274aa74fc2833252d4a06ec65cc.yaml +22 -0
- data/bugs/project.yaml +18 -0
- data/data/ditz-str/blue-check.png +0 -0
- data/data/ditz-str/close.rhtml +39 -0
- data/data/ditz-str/component.rhtml +38 -0
- data/data/ditz-str/dropdown.css +11 -0
- data/data/ditz-str/dropdown.js +58 -0
- data/data/ditz-str/edit_issue.rhtml +53 -0
- data/data/ditz-str/green-bar.png +0 -0
- data/data/ditz-str/green-check.png +0 -0
- data/data/ditz-str/header.gif +0 -0
- data/data/ditz-str/header_over.gif +0 -0
- data/data/ditz-str/index.rhtml +148 -0
- data/data/ditz-str/issue.rhtml +152 -0
- data/data/ditz-str/issue_table.rhtml +28 -0
- data/data/ditz-str/new_component.rhtml +28 -0
- data/data/ditz-str/new_issue.rhtml +57 -0
- data/data/ditz-str/new_release.rhtml +29 -0
- data/data/ditz-str/plugins/git-sync.rb +83 -0
- data/data/ditz-str/plugins/git.rb +153 -0
- data/data/ditz-str/plugins/issue-claiming.rb +174 -0
- data/data/ditz-str/red-check.png +0 -0
- data/data/ditz-str/release.rhtml +111 -0
- data/data/ditz-str/style.css +236 -0
- data/data/ditz-str/unassigned.rhtml +37 -0
- data/data/ditz-str/yellow-bar.png +0 -0
- data/ditz-str.gemspec +121 -0
- data/lib/ditzstr/brick.rb +251 -0
- data/lib/ditzstr/file-storage.rb +54 -0
- data/lib/ditzstr/hook.rb +67 -0
- data/lib/ditzstr/html.rb +104 -0
- data/lib/ditzstr/lowline.rb +201 -0
- data/lib/ditzstr/model-objects.rb +346 -0
- data/lib/ditzstr/model.rb +265 -0
- data/lib/ditzstr/operator.rb +593 -0
- data/lib/ditzstr/trollop.rb +614 -0
- data/lib/ditzstr/util.rb +61 -0
- data/lib/ditzstr/view.rb +16 -0
- data/lib/ditzstr/views.rb +157 -0
- data/lib/ditzstr.rb +69 -0
- data/man/ditz.1 +38 -0
- data/test/helper.rb +18 -0
- data/test/test_ditz-str.rb +7 -0
- metadata +219 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
|
5
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
6
|
+
<head>
|
7
|
+
<title>New Issue</title>
|
8
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
9
|
+
<link rel="stylesheet" href="style.css" type="text/css" />
|
10
|
+
</head>
|
11
|
+
|
12
|
+
<body>
|
13
|
+
|
14
|
+
<div class="main">
|
15
|
+
|
16
|
+
<h1>New Issue</h1>
|
17
|
+
<div class="backptr"><%= link_to "index", "« #{@project.name} project page" %></div>
|
18
|
+
<%= "<form name=\"new_issue_form\" method=\"post\">" %>
|
19
|
+
Title<br/><input type="text" name="title" size="80"/><br/>
|
20
|
+
Description<br/><textarea cols="80" rows="10" name="description"/></textarea><br/>
|
21
|
+
Type<br/><select name="type">
|
22
|
+
<option>bugfix</option>
|
23
|
+
<option>feature</option>
|
24
|
+
<option>task</option>
|
25
|
+
</select><br/>
|
26
|
+
|
27
|
+
Component<br/>
|
28
|
+
<select name="component">
|
29
|
+
<% @project.components.each do |c| %>
|
30
|
+
<% if c.name==options[:component] %>
|
31
|
+
<%= "<option selected=\"true\">#{c.name}</option>" %>
|
32
|
+
<% else %>
|
33
|
+
<%= "<option>#{c.name}</option>" %>
|
34
|
+
<% end %>
|
35
|
+
<% end %></select><br/>
|
36
|
+
|
37
|
+
Release<br/>
|
38
|
+
<select name="release">
|
39
|
+
<% upcoming_rels.each do |r| %>
|
40
|
+
<% if r.name==options[:release] %>
|
41
|
+
<%= "<option selected=\"true\">#{r.name}</option>" %>
|
42
|
+
<% else %>
|
43
|
+
<%= "<option>#{r.name}</option>" %>
|
44
|
+
<% end %>
|
45
|
+
<% end %></select><br/>
|
46
|
+
|
47
|
+
Creator<br/>
|
48
|
+
<%= "<input type=\"text\" size=\"80\" value=\"#{options[:creator]}\"/><br/>" %>
|
49
|
+
<textarea cols="80" rows="10" name="comments"/></textarea><br/><br/>
|
50
|
+
<input type="submit" value="Add Issue"/>
|
51
|
+
</form>
|
52
|
+
|
53
|
+
</div>
|
54
|
+
<div class="footer">Generated by <a href="http://ditz.rubyforge.org/">ditz</a>.</div>
|
55
|
+
|
56
|
+
</body>
|
57
|
+
</html>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
|
5
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
6
|
+
<head>
|
7
|
+
<%= "<title>#{@project.name} - New Release</title>" %>
|
8
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
9
|
+
<link rel="stylesheet" href="style.css" type="text/css" />
|
10
|
+
</head>
|
11
|
+
|
12
|
+
<body>
|
13
|
+
|
14
|
+
<div class="main">
|
15
|
+
|
16
|
+
<h1>New Release</h1>
|
17
|
+
<div class="backptr"><%= link_to "index", "« #{@project.name} project page" %></div>
|
18
|
+
|
19
|
+
<form name="new_issue_form" method="post">
|
20
|
+
Name<br/><input type="text" name="name" size="80"/><br/>
|
21
|
+
Comments<br/><textarea cols="80" rows="10" name="comments"/></textarea><br/>
|
22
|
+
<input type="submit" value="Add Release"/>
|
23
|
+
</form>
|
24
|
+
|
25
|
+
</div>
|
26
|
+
<div class="footer">Generated by <a href="http://ditz.rubyforge.org/">ditz</a>.</div>
|
27
|
+
|
28
|
+
</body>
|
29
|
+
</html>
|
@@ -0,0 +1,83 @@
|
|
1
|
+
## git-sync ditz plugin
|
2
|
+
##
|
3
|
+
## This plugin is useful for when you want synchronized, non-distributed issue
|
4
|
+
## coordination with other developers, and you're using git. It allows you to
|
5
|
+
## synchronize issue updates with other developers by using the 'ditz sync'
|
6
|
+
## command, which does all the git work of sending and receiving issue change
|
7
|
+
## for you. However, you have to set things up in a very specific way for this
|
8
|
+
## to work:
|
9
|
+
##
|
10
|
+
## 1. Your ditz state must be on a separate branch. I recommend calling it
|
11
|
+
## 'bugs'. Create this branch, do a ditz init, and push it to the remote
|
12
|
+
## repo. (This means you won't be able to mingle issue change and code
|
13
|
+
## change in the same commits. If you care.)
|
14
|
+
## 2. Make a checkout of the bugs branch in a separate directory, but NOT in
|
15
|
+
## your code checkout. If you're developing in a directory called "project",
|
16
|
+
## I recommend making a ../project-bugs/ directory, cloning the repo there
|
17
|
+
## as well, and keeping that directory checked out to the 'bugs' branch.
|
18
|
+
## (There are various complicated things you can do to make that directory
|
19
|
+
## share git objects with your code directory, but I wouldn't bother unless
|
20
|
+
## you really care about disk space. Just make it an independent clone.)
|
21
|
+
## 3. Set that directory as your issue-dir in your .ditz-config file in your
|
22
|
+
## code checkout directory. (This file should be in .gitignore, btw.)
|
23
|
+
## 4. Run 'ditz reconfigure' and fill in the local branch name, remote
|
24
|
+
## branch name, and remote repo for the issue tracking branch.
|
25
|
+
##
|
26
|
+
## Once that's set up, 'ditz sync' will change to the bugs checkout dir, bundle
|
27
|
+
## up any changes you've made to issue status, push them to the remote repo,
|
28
|
+
## and pull any new changes in too. All ditz commands will read from your bugs
|
29
|
+
## directory, so you should be able to use ditz without caring about where
|
30
|
+
## things are anymore.
|
31
|
+
##
|
32
|
+
## This complicated setup is necessary to avoid accidentally mingling code
|
33
|
+
## change and issue change. With this setup, issue change is synchronized,
|
34
|
+
## but how you synchronize code is still up to you.
|
35
|
+
##
|
36
|
+
## Usage:
|
37
|
+
## 0. read all the above text very carefully
|
38
|
+
## 1. add a line "- git-sync" to the .ditz-plugins file in the project
|
39
|
+
## root
|
40
|
+
## 2. run 'ditz reconfigure' and answer its questions
|
41
|
+
## 3. run 'ditz sync' with abandon
|
42
|
+
|
43
|
+
module DitzStr
|
44
|
+
|
45
|
+
class Config
|
46
|
+
field :git_sync_local_branch, :prompt => "Local bugs branch name for ditz sync", :default => "bugs"
|
47
|
+
field :git_sync_remote_branch, :prompt => "Remote bugs branch name for ditz sync", :default => "bugs"
|
48
|
+
field :git_sync_remote_repo, :prompt => "Remote bugs repo name for ditz sync", :default => "origin"
|
49
|
+
end
|
50
|
+
|
51
|
+
class Operator
|
52
|
+
operation :sync, "Sync the repo containing ditz via git" do
|
53
|
+
opt :dry_run, "Dry run: print the commants, but don't execute them", :short => "n"
|
54
|
+
end
|
55
|
+
def sync project, config, opts
|
56
|
+
unless config.git_sync_local_branch
|
57
|
+
$stderr.puts "Please run ditz reconfigure and set the local and remote branch names"
|
58
|
+
return
|
59
|
+
end
|
60
|
+
|
61
|
+
Dir.chdir $project_root
|
62
|
+
puts "[in #{$project_root}]"
|
63
|
+
sh "git add *.yaml", :force => true, :fake => opts[:dry_run]
|
64
|
+
sh "git commit -m 'issue updates'", :force => true, :fake => opts[:dry_run]
|
65
|
+
sh "git pull", :fake => opts[:dry_run]
|
66
|
+
sh "git push #{config.git_sync_remote_repo} #{config.git_sync_local_branch}:#{config.git_sync_remote_branch}", :fake => opts[:dry_run]
|
67
|
+
puts
|
68
|
+
puts "Ditz issue state synchronized."
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def sh s, opts={}
|
74
|
+
puts "+ #{s}"
|
75
|
+
return if opts[:fake]
|
76
|
+
unless system(s) || opts[:force]
|
77
|
+
$stderr.puts "non-zero (#{$?.exitstatus}) exit code: #{s}"
|
78
|
+
exit(-1)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
## git ditz plugin
|
2
|
+
##
|
3
|
+
## This plugin allows issues to be associated with git commits and git
|
4
|
+
## branches. Git commits can be easily tagged with a ditz issue with the 'ditz
|
5
|
+
## commit' command, and both 'ditz show' and the ditz HTML output will then
|
6
|
+
## contain a list of associated commits for each issue.
|
7
|
+
##
|
8
|
+
## Issues can also be assigned a single git feature branch. In this case, all
|
9
|
+
## commits on that branch will listed as commits for that issue. This
|
10
|
+
## particular feature is fairly rudimentary, however---it assumes the reference
|
11
|
+
## point is the 'master' branch, and once the feature branch is merged back
|
12
|
+
## into master, the list of commits disappears.
|
13
|
+
##
|
14
|
+
## Two configuration variables are added, which, when specified, are used to
|
15
|
+
## construct HTML links for the git commit id and branch names in the generated
|
16
|
+
## HTML output.
|
17
|
+
##
|
18
|
+
## Commands added:
|
19
|
+
## ditz set-branch: set the git branch of an issue
|
20
|
+
## ditz commit: run git-commit, and insert the issue id into the commit
|
21
|
+
## message.
|
22
|
+
##
|
23
|
+
## Usage:
|
24
|
+
## 1. add a line "- git" to the .ditz-plugins file in the project root
|
25
|
+
## 2. run ditz reconfigure, and enter the URL prefixes, if any, from
|
26
|
+
## which to create commit and branch links.
|
27
|
+
## 3. use 'ditz commit' with abandon.
|
28
|
+
|
29
|
+
require 'time'
|
30
|
+
|
31
|
+
module DitzStr
|
32
|
+
class Issue
|
33
|
+
field :git_branch, :ask => false
|
34
|
+
|
35
|
+
def git_commits
|
36
|
+
return @git_commits if @git_commits
|
37
|
+
|
38
|
+
filters = ["--grep=\"DitzStr-issue: #{id}\""]
|
39
|
+
filters << "master..#{git_branch}" if git_branch
|
40
|
+
|
41
|
+
output = filters.map do |f|
|
42
|
+
`git log --pretty=format:\"%aD\t%an <%ae>\t%h\t%s\" #{f}`
|
43
|
+
end.join
|
44
|
+
|
45
|
+
@git_commits = output.split(/\n/).map { |l| l.split("\t") }.
|
46
|
+
map { |date, email, hash, msg| [Time.parse(date).utc, email, hash, msg] }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Config
|
51
|
+
field :git_commit_url_prefix, :prompt => "URL prefix to link git commits to", :default => ""
|
52
|
+
field :git_branch_url_prefix, :prompt => "URL prefix to link git branches to", :default => ""
|
53
|
+
end
|
54
|
+
|
55
|
+
class ScreenView
|
56
|
+
add_to_view :issue_summary do |issue, config|
|
57
|
+
" Git branch: #{issue.git_branch || 'none'}\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
add_to_view :issue_details do |issue, config|
|
61
|
+
commits = issue.git_commits[0...5]
|
62
|
+
next if commits.empty?
|
63
|
+
"Recent commits:\n" + commits.map do |date, email, hash, msg|
|
64
|
+
"- #{msg} [#{hash}] (#{email.shortened_email}, #{date.ago} ago)\n"
|
65
|
+
end.join + "\n"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class HtmlView
|
70
|
+
add_to_view :issue_summary do |issue, config|
|
71
|
+
next unless issue.git_branch
|
72
|
+
[<<EOS, { :issue => issue, :url_prefix => config.git_branch_url_prefix }]
|
73
|
+
<tr>
|
74
|
+
<td class='attrname'>Git branch:</td>
|
75
|
+
<td class='attrval'><%= url_prefix && !url_prefix.blank? ? link_to([url_prefix, issue.git_branch].join, issue.git_branch) : h(issue.git_branch) %></td>
|
76
|
+
</tr>
|
77
|
+
EOS
|
78
|
+
end
|
79
|
+
|
80
|
+
add_to_view :issue_details do |issue, config|
|
81
|
+
commits = issue.git_commits
|
82
|
+
next if commits.empty?
|
83
|
+
|
84
|
+
[<<EOS, { :commits => commits, :url_prefix => config.git_commit_url_prefix }]
|
85
|
+
<h2>Commits for this issue</h2>
|
86
|
+
<table class="log">
|
87
|
+
<% commits.each_with_index do |(time, who, hash, msg), i| %>
|
88
|
+
<tr class="<%= i % 2 == 0 ? "even-row" : "odd-row" %>">
|
89
|
+
<td class="time"><%=t time %></td>
|
90
|
+
<td class="person"><%=obscured_email who %></td>
|
91
|
+
<td class="message"><%=h msg %> [<%= url_prefix && !url_prefix.blank? ? link_to([url_prefix, hash].join, hash) : hash %>]</td>
|
92
|
+
</tr>
|
93
|
+
<tr><td></td></tr>
|
94
|
+
<% end %>
|
95
|
+
</table>
|
96
|
+
EOS
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class Operator
|
101
|
+
operation :set_branch, "Set the git feature branch of an issue", :issue, :maybe_string
|
102
|
+
def set_branch project, config, issue, maybe_string
|
103
|
+
puts "Issue #{issue.name} currently " + if issue.git_branch
|
104
|
+
"assigned to git branch #{issue.git_branch.inspect}."
|
105
|
+
else
|
106
|
+
"not assigned to any git branch."
|
107
|
+
end
|
108
|
+
|
109
|
+
branch = maybe_string || ask("Git feature branch name:")
|
110
|
+
return unless branch
|
111
|
+
|
112
|
+
if branch == issue.git_branch
|
113
|
+
raise Error, "issue #{issue.name} already assigned to branch #{issue.git_branch.inspect}"
|
114
|
+
end
|
115
|
+
|
116
|
+
puts "Assigning to branch #{branch.inspect}."
|
117
|
+
issue.git_branch = branch
|
118
|
+
end
|
119
|
+
|
120
|
+
operation :commit, "Runs git-commit and auto-fills the issue name in the commit message", :issue do
|
121
|
+
opt :all, "commit all changed files", :short => "-a", :default => false
|
122
|
+
opt :verbose, "show diff between HEAD and what would be committed", \
|
123
|
+
:short => "-v", :default => false
|
124
|
+
opt :message, "Use the given <s> as the commit message.", \
|
125
|
+
:short => "-m", :type => :string
|
126
|
+
opt :edit, "Further edit the message, even if --message is given.", :short => "-e", :default => false
|
127
|
+
end
|
128
|
+
|
129
|
+
def commit project, config, opts, issue
|
130
|
+
opts[:edit] = true if opts[:message].nil?
|
131
|
+
|
132
|
+
args = {
|
133
|
+
:verbose => "--verbose",
|
134
|
+
:all => "--all",
|
135
|
+
:edit => "--edit",
|
136
|
+
}.map { |k, v| opts[k] ? v : "" }.join(" ")
|
137
|
+
|
138
|
+
comment = "# #{issue.name}: #{issue.title}"
|
139
|
+
tag = "DitzStr-issue: #{issue.id}"
|
140
|
+
message = if opts[:message] && !opts[:edit]
|
141
|
+
"#{opts[:message]}\n\n#{tag}"
|
142
|
+
elsif opts[:message] && opts[:edit]
|
143
|
+
"#{opts[:message]}\n\n#{comment}\n#{tag}"
|
144
|
+
else
|
145
|
+
"#{comment}\n#{tag}"
|
146
|
+
end
|
147
|
+
|
148
|
+
message = message.gsub("\"", "\\\"")
|
149
|
+
exec "git commit #{args} --message=\"#{message}\""
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
## issue-claiming ditz plugin
|
2
|
+
##
|
3
|
+
## This plugin allows people to claim issues. This is useful for avoiding
|
4
|
+
## duplication of work---you can check to see if someone's claimed an
|
5
|
+
## issue before starting to work on it, and you can let people know what
|
6
|
+
## you're working on.
|
7
|
+
##
|
8
|
+
## Commands added:
|
9
|
+
## ditz claim: claim an issue for yourself
|
10
|
+
## ditz unclaim: unclaim a claimed issue
|
11
|
+
## ditz mine: show all issues claimed by you
|
12
|
+
## ditz claimed: show all claimed issues, by developer
|
13
|
+
## ditz unclaimed: show all unclaimed issues
|
14
|
+
##
|
15
|
+
## Usage:
|
16
|
+
## 1. add a line "- issue-claiming" to the .ditz-plugins file in the project
|
17
|
+
## root
|
18
|
+
## 2. use the above commands to abandon
|
19
|
+
|
20
|
+
module DitzStr
|
21
|
+
class Issue
|
22
|
+
field :claimer, :ask => false
|
23
|
+
|
24
|
+
def claim who, comment, force=false
|
25
|
+
raise Error, "already claimed by #{claimer}" if claimer && !force
|
26
|
+
log "issue claimed", who, comment
|
27
|
+
self.claimer = who
|
28
|
+
end
|
29
|
+
|
30
|
+
def unclaim who, comment, force=false
|
31
|
+
raise Error, "not claimed" unless claimer
|
32
|
+
raise Error, "can only be unclaimed by #{claimer}" unless claimer == who || force
|
33
|
+
if claimer == who
|
34
|
+
log "issue unclaimed", who, comment
|
35
|
+
else
|
36
|
+
log "unassigned from #{claimer}", who, comment
|
37
|
+
end
|
38
|
+
self.claimer = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def claimed?; claimer end
|
42
|
+
def unclaimed?; !claimed? end
|
43
|
+
end
|
44
|
+
|
45
|
+
class ScreenView
|
46
|
+
add_to_view :issue_summary do |issue, config|
|
47
|
+
" Claimed by: #{issue.claimer || 'none'}\n"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class HtmlView
|
52
|
+
add_to_view :issue_summary do |issue, config|
|
53
|
+
next unless issue.claimer
|
54
|
+
[<<EOS, { :issue => issue }]
|
55
|
+
<tr>
|
56
|
+
<td class='attrname'>Claimed by:</td>
|
57
|
+
<td class='attrval'><%= h(issue.claimer) %></td>
|
58
|
+
</tr>
|
59
|
+
EOS
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Operator
|
64
|
+
alias :__issue_claiming_start :start
|
65
|
+
def start project, config, opts, issue
|
66
|
+
if issue.claimed? && issue.claimer != config.user
|
67
|
+
raise Error, "issue #{issue.name} claimed by #{issue.claimer}"
|
68
|
+
else
|
69
|
+
__issue_claiming_start project, config, opts, issue
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
alias :__issue_claiming_stop :stop
|
74
|
+
def stop project, config, opts, issue
|
75
|
+
if issue.claimed? && issue.claimer != config.user
|
76
|
+
raise Error, "issue #{issue.name} claimed by #{issue.claimer}"
|
77
|
+
else
|
78
|
+
__issue_claiming_stop project, config, opts, issue
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
alias :__issue_claiming_close :close
|
83
|
+
def close project, config, opts, issue
|
84
|
+
if issue.claimed? && issue.claimer != config.user
|
85
|
+
raise Error, "issue #{issue.name} claimed by #{issue.claimer}"
|
86
|
+
else
|
87
|
+
__issue_claiming_close project, config, opts, issue
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
operation :claim, "Claim an issue for yourself", :issue do
|
92
|
+
opt :force, "Claim this issue even if someone else has claimed it", :default => false
|
93
|
+
end
|
94
|
+
def claim project, config, opts, issue
|
95
|
+
puts "Claiming issue #{issue.name}: #{issue.title}."
|
96
|
+
comment = ask_multiline "Comments" unless $opts[:no_comment]
|
97
|
+
issue.claim config.user, comment, opts[:force]
|
98
|
+
puts "Issue #{issue.name} marked as claimed by #{config.user}"
|
99
|
+
end
|
100
|
+
|
101
|
+
operation :unclaim, "Unclaim a claimed issue", :issue do
|
102
|
+
opt :force, "Unclaim this issue even if it's claimed by someone else", :default => false
|
103
|
+
end
|
104
|
+
def unclaim project, config, opts, issue
|
105
|
+
puts "Unclaiming issue #{issue.name}: #{issue.title}."
|
106
|
+
comment = ask_multiline "Comments" unless $opts[:no_comment]
|
107
|
+
issue.unclaim config.user, comment, opts[:force]
|
108
|
+
puts "Issue #{issue.name} marked as unclaimed."
|
109
|
+
end
|
110
|
+
|
111
|
+
operation :mine, "Show all issues claimed by you", :maybe_release do
|
112
|
+
opt :all, "Show all issues, not just open ones"
|
113
|
+
end
|
114
|
+
def mine project, config, opts, releases
|
115
|
+
releases ||= project.unreleased_releases + [:unassigned]
|
116
|
+
releases = [*releases]
|
117
|
+
|
118
|
+
issues = project.issues.select do |i|
|
119
|
+
r = project.release_for(i.release) || :unassigned
|
120
|
+
releases.member?(r) && i.claimer == config.user && (opts[:all] || i.open?)
|
121
|
+
end
|
122
|
+
if issues.empty?
|
123
|
+
puts "No issues."
|
124
|
+
else
|
125
|
+
print_todo_list_by_release_for project, issues
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
operation :claimed, "Show claimed issues by claimer", :maybe_release do
|
130
|
+
opt :all, "Show all issues, not just open ones"
|
131
|
+
end
|
132
|
+
def claimed project, config, opts, releases
|
133
|
+
releases ||= project.unreleased_releases + [:unassigned]
|
134
|
+
releases = [*releases]
|
135
|
+
|
136
|
+
issues = project.issues.inject({}) do |h, i|
|
137
|
+
r = project.release_for(i.release) || :unassigned
|
138
|
+
if i.claimed? && (opts[:all] || i.open?) && releases.member?(r)
|
139
|
+
(h[i.claimer] ||= []) << i
|
140
|
+
end
|
141
|
+
h
|
142
|
+
end
|
143
|
+
|
144
|
+
if issues.empty?
|
145
|
+
puts "No issues."
|
146
|
+
else
|
147
|
+
issues.keys.sort.each do |c|
|
148
|
+
puts "#{c}:"
|
149
|
+
puts todo_list_for(issues[c], :show_release => true)
|
150
|
+
puts
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
operation :unclaimed, "Show all unclaimed issues", :maybe_release do
|
156
|
+
opt :all, "Show all issues, not just open ones"
|
157
|
+
end
|
158
|
+
def unclaimed project, config, opts, releases
|
159
|
+
releases ||= project.unreleased_releases + [:unassigned]
|
160
|
+
releases = [*releases]
|
161
|
+
|
162
|
+
issues = project.issues.select do |i|
|
163
|
+
r = project.release_for(i.release) || :unassigned
|
164
|
+
releases.member?(r) && i.claimer.nil? && (opts[:all] || i.open?)
|
165
|
+
end
|
166
|
+
if issues.empty?
|
167
|
+
puts "No issues."
|
168
|
+
else
|
169
|
+
print_todo_list_by_release_for project, issues
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
Binary file
|
@@ -0,0 +1,111 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
|
5
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
6
|
+
<head>
|
7
|
+
<title><%= project.name %> release <%= release.name %></title>
|
8
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
9
|
+
<link rel="stylesheet" href="style.css" type="text/css" />
|
10
|
+
<link rel="stylesheet" href="dropdown.css" type="text/css"/>
|
11
|
+
<script type="text/javascript" src="dropdown.js">
|
12
|
+
</script>
|
13
|
+
</head>
|
14
|
+
<body>
|
15
|
+
|
16
|
+
<div class="main">
|
17
|
+
|
18
|
+
<h1><%= project.name %> release <%= release.name %></h1>
|
19
|
+
<div class="menu">
|
20
|
+
<% if not brickargs.empty? %>
|
21
|
+
<dl class="dropdown">
|
22
|
+
<%= "<dt id=\"newissue-ddheader\" onmouseover=\"ddMenu('newissue',1)\" onmouseout=\"ddMenu('newissue',-1)\" onclick=\"location.href='/new_issue.html?release=#{release.name}'\" >New Issue</dt>" %>
|
23
|
+
</dl>
|
24
|
+
<% end %>
|
25
|
+
</div>
|
26
|
+
<br/><br/><br/>
|
27
|
+
|
28
|
+
<div class="backptr"><%= link_to "index", "« #{project.name} project page" %></div>
|
29
|
+
|
30
|
+
<table>
|
31
|
+
<tbody>
|
32
|
+
<tr>
|
33
|
+
<td class="attrname">Status:</td>
|
34
|
+
<td class="attrval"><%= release.status %></td>
|
35
|
+
</tr>
|
36
|
+
<% if release.released? %>
|
37
|
+
<tr>
|
38
|
+
<td class="attrname">Release time:</td>
|
39
|
+
<td class="attrval"><%=t release.release_time %></td>
|
40
|
+
</tr>
|
41
|
+
<% end %>
|
42
|
+
<tr>
|
43
|
+
<td class="attrname">Completion:</td>
|
44
|
+
<td>
|
45
|
+
<%
|
46
|
+
num_done = issues.count_of { |i| i.closed? }
|
47
|
+
pct_done = issues.size == 0 ? 1.0 : (num_done.to_f / issues.size.to_f)
|
48
|
+
%>
|
49
|
+
<%= progress_meter pct_done %>
|
50
|
+
<%= sprintf "%.0f%%", pct_done * 100.0 %>
|
51
|
+
</td>
|
52
|
+
</tr>
|
53
|
+
<tr><td></td><td class="attrval">
|
54
|
+
<%= num_done %> / <%= issues.size %> issues
|
55
|
+
</td></tr>
|
56
|
+
</tbody>
|
57
|
+
</table>
|
58
|
+
|
59
|
+
<h2>Issues</h2>
|
60
|
+
<% if issues.empty? %>
|
61
|
+
<p>No issues assigned to this release.</p>
|
62
|
+
<% else %>
|
63
|
+
<%= render "issue_table", :show_component => false, :show_release => false %>
|
64
|
+
<% end %>
|
65
|
+
|
66
|
+
<h2>Recent activity for this release</h2>
|
67
|
+
<table class="log">
|
68
|
+
<tbody>
|
69
|
+
<% issues.map { |i| i.log_events.map { |e| [e, i] } }.
|
70
|
+
flatten_one_level.
|
71
|
+
sort_by { |e| e.first.first }.
|
72
|
+
reverse[0 ... 10].
|
73
|
+
each_with_index do |((date, who, what, comment), i), idx| %>
|
74
|
+
<tr class="<%= idx % 2 == 0 ? "even-row" : "odd-row" %>">
|
75
|
+
<td class="date"><%= date.pretty_date %></td>
|
76
|
+
<td class="issuename">
|
77
|
+
<%= issue_link_for i, :status_image => true %>
|
78
|
+
</td>
|
79
|
+
<td> <%= what %> </td>
|
80
|
+
</tr>
|
81
|
+
<tr><td></td></tr>
|
82
|
+
<% end %>
|
83
|
+
</tbody>
|
84
|
+
</table>
|
85
|
+
|
86
|
+
<h2>Release log</h2>
|
87
|
+
<table class="log">
|
88
|
+
<tbody>
|
89
|
+
<% release.log_events.reverse.each_with_index do |(time, who, what, comment), i| %>
|
90
|
+
<tr class="<%= i % 2 == 0 ? "even-row" : "odd-row" %>">
|
91
|
+
<td class="date"><%=h time %></td>
|
92
|
+
<td class="person"><%=obscured_email who %></td>
|
93
|
+
<td class="message"><%=h what %></td>
|
94
|
+
</tr>
|
95
|
+
<tr><td colspan="3" class="logcomment">
|
96
|
+
<% if comment.empty? %>
|
97
|
+
<% else %>
|
98
|
+
<%= link_issue_names project, comment %>
|
99
|
+
<% end %>
|
100
|
+
</td></tr>
|
101
|
+
<tr><td></td></tr>
|
102
|
+
<% end %>
|
103
|
+
</tbody>
|
104
|
+
</table>
|
105
|
+
|
106
|
+
</div>
|
107
|
+
|
108
|
+
<div class="footer">Generated by <a href="http://ditz.rubyforge.org/">ditz</a>.</div>
|
109
|
+
|
110
|
+
</body>
|
111
|
+
</html>
|