ditz 0.4 → 0.5

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.
@@ -0,0 +1,42 @@
1
+ Changelog
2
+ INSTALL
3
+ LICENSE
4
+ Manifest.txt
5
+ PLUGINS.txt
6
+ README.txt
7
+ Rakefile
8
+ ReleaseNotes
9
+ bin/ditz
10
+ contrib/completion/_ditz.zsh
11
+ contrib/completion/ditz.bash
12
+ lib/blue-check.png
13
+ lib/component.rhtml
14
+ lib/ditz.rb
15
+ lib/file-storage.rb
16
+ lib/green-bar.png
17
+ lib/green-check.png
18
+ lib/hook.rb
19
+ lib/html.rb
20
+ lib/index.rhtml
21
+ lib/issue.rhtml
22
+ lib/issue_table.rhtml
23
+ lib/lowline.rb
24
+ lib/model-objects.rb
25
+ lib/model.rb
26
+ lib/operator.rb
27
+ lib/plugins/git-sync.rb
28
+ lib/plugins/git.rb
29
+ lib/plugins/issue-claiming.rb
30
+ lib/red-check.png
31
+ lib/release.rhtml
32
+ lib/style.css
33
+ lib/trollop.rb
34
+ lib/unassigned.rhtml
35
+ lib/util.rb
36
+ lib/view.rb
37
+ lib/views.rb
38
+ lib/yellow-bar.png
39
+ man/ditz.1
40
+ setup.rb
41
+ www/index.html
42
+ www/main.css
@@ -0,0 +1,99 @@
1
+ Ditz plugin documentation
2
+
3
+ Shipped plugins:
4
+ 1. git
5
+ 2. git-sync
6
+ 3. issue-claiming
7
+
8
+ git
9
+ ---
10
+
11
+ This plugin allows issues to be associated with git commits and git
12
+ branches. Git commits can be easily tagged with a ditz issue with the 'ditz
13
+ commit' command, and both 'ditz show' and the ditz HTML output will then
14
+ contain a list of associated commits for each issue.
15
+
16
+ Issues can also be assigned a single git feature branch. In this case, all
17
+ commits on that branch will listed as commits for that issue. This
18
+ particular feature is fairly rudimentary, however---it assumes the reference
19
+ point is the 'master' branch, and once the feature branch is merged back
20
+ into master, the list of commits disappears.
21
+
22
+ Two configuration variables are added, which, when specified, are used to
23
+ construct HTML links for the git commit id and branch names in the generated
24
+ HTML output.
25
+
26
+ Commands added:
27
+ ditz set-branch: set the git branch of an issue
28
+ ditz commit: run git-commit, and insert the issue id into the commit
29
+ message.
30
+
31
+ Usage:
32
+ 1. add a line "- git" to the .ditz-plugins file in the project root
33
+ 2. run ditz reconfigure, and enter the URL prefixes, if any, from
34
+ which to create commit and branch links.
35
+ 3. use 'ditz commit' with abandon.
36
+
37
+ git-sync
38
+ --------
39
+
40
+ This plugin is useful for when you want synchronized, non-distributed issue
41
+ coordination with other developers, and you're using git. It allows you to
42
+ synchronize issue updates with other developers by using the 'ditz sync'
43
+ command, which does all the git work of sending and receiving issue change
44
+ for you. However, you have to set things up in a very specific way for this
45
+ to work:
46
+
47
+ 1. Your ditz state must be on a separate branch. I recommend calling it
48
+ 'bugs'. Create this branch, do a ditz init, and push it to the remote
49
+ repo. (This means you won't be able to mingle issue change and code
50
+ change in the same commits. If you care.)
51
+ 2. Make a checkout of the bugs branch in a separate directory, but NOT in
52
+ your code checkout. If you're developing in a directory called "project",
53
+ I recommend making a ../project-bugs/ directory, cloning the repo there
54
+ as well, and keeping that directory checked out to the 'bugs' branch.
55
+ (There are various complicated things you can do to make that directory
56
+ share git objects with your code directory, but I wouldn't bother unless
57
+ you really care about disk space. Just make it an independent clone.)
58
+ 3. Set that directory as your issue-dir in your .ditz-config file in your
59
+ code checkout directory. (This file should be in .gitignore, btw.)
60
+ 4. Run 'ditz reconfigure' and fill in the local branch name, remote
61
+ branch name, and remote repo for the issue tracking branch.
62
+
63
+ Once that's set up, 'ditz sync' will change to the bugs checkout dir, bundle
64
+ up any changes you've made to issue status, push them to the remote repo,
65
+ and pull any new changes in too. All ditz commands will read from your bugs
66
+ directory, so you should be able to use ditz without caring about where
67
+ things are anymore.
68
+
69
+ This complicated setup is necessary to avoid accidentally mingling code
70
+ change and issue change. With this setup, issue change is synchronized,
71
+ but how you synchronize code is still up to you.
72
+
73
+ Usage:
74
+ 0. read all the above text very carefully
75
+ 1. add a line "- git-sync" to the .ditz-plugins file in the project
76
+ root
77
+ 2. run 'ditz reconfigure' and answer its questions
78
+ 3. run 'ditz sync' with abandon
79
+
80
+ issue-claiming
81
+ --------------
82
+
83
+ This plugin allows people to claim issues. This is useful for avoiding
84
+ duplication of work---you can check to see if someone's claimed an
85
+ issue before starting to work on it, and you can let people know what
86
+ you're working on.
87
+
88
+ Commands added:
89
+ ditz claim: claim an issue for yourself
90
+ ditz unclaim: unclaim a claimed issue
91
+ ditz mine: show all issues claimed by you
92
+ ditz claimed: show all claimed issues, by developer
93
+ ditz unclaimed: show all unclaimed issues
94
+
95
+ Usage:
96
+ 1. add a line "- issue-claiming" to the .ditz-plugins file in the project
97
+ root
98
+ 2. use the above commands to abandon
99
+
data/README.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  == ditz
2
2
 
3
- by William Morgan <wmorgan-ditz@masanjin.net>
3
+ by William Morgan <wmorgan-ditz at the masanjin dot nets>
4
4
 
5
5
  http://ditz.rubyforge.org
6
6
 
@@ -14,23 +14,39 @@ Ditz maintains an issue database directory on disk, with files written in a
14
14
  line-based and human-editable format. This directory can be kept under version
15
15
  control, alongside project code.
16
16
 
17
- There are different ways to use ditz:
17
+ Ditz provides a simple, console-based interface for creating and updating the
18
+ issue database files, and some basic static HTML generation capabilities for
19
+ producing world-readable status pages (for a demo, see the ditz ditz page).
18
20
 
19
- 1. Treat issue change the same as code change: include it as part of commits,
20
- and merge it with changes from other developers. (Resolving conflicts in
21
- the usual manner.)
22
- 2. Keep the issue database in the repository but in a separate branch. Issue
23
- changes can be managed by your VCS, but is not tied directly to commits.
24
- 3. Keep the issue database separate and not under VCS at all.
21
+ Ditz includes a robust plugin system for adding commands, model fields, and
22
+ modifying output. See PLUGINS.txt for documentation on the pre-shipped plugins.
25
23
 
26
- Your particular usage will depend on what you want to get out of ditz.
24
+ Ditz currently offers no central public method of bug submission.
27
25
 
28
- Ditz provides a simple, console-based interface for creating and updating the
29
- issue database file, and some rudimentary HTML generation capabilities for
30
- producing world-readable status pages. It currently offers no central public
31
- method of bug submission.
26
+ == USING DITZ
27
+
28
+ There are several different ways to use Ditz:
29
+
30
+ 1. Treat issue change the same as code change: include it as part of commits,
31
+ and merge it with changes from other developers, resolving conflicts in the
32
+ usual manner.
33
+ 2. Keep the issue database in the repository but in a separate branch. Issue
34
+ changes can be managed by your VCS, but is not tied directly to code
35
+ commits.
36
+ 3. Keep the issue database separate and not under VCS at all.
37
+
38
+ All of these options are supported; the choice of which to use depends on your
39
+ workflow.
32
40
 
33
- == SYNOPSIS
41
+ Option #1 is probably most appropriate for the unsynchronized, distributed
42
+ development, since it allows individual developers to modify issue state with a
43
+ minimum of hassle. Option #2 is most suitable for synchronized development, as
44
+ issue state change can be transmitted independently of code change (see also
45
+ the git-sync plugin) and can act as a sychronization mechanism. Option #3 is
46
+ only useful with some other distribution mechanism, like a central web
47
+ interface.
48
+
49
+ == COMMANDLINE SYNOPSIS
34
50
 
35
51
  # set up project. creates the bugs.yaml file.
36
52
  1. ditz init
@@ -54,16 +70,17 @@ method of bug submission.
54
70
 
55
71
  == THE DITZ DATA MODEL
56
72
 
57
- Ditz includes the bare minimum set of features necessary for open-source
58
- development. Features like time spent, priority, assignment of tasks to
59
- developers, due dates, etc. are purposely excluded.
73
+ By default, Ditz includes the bare minimum set of features necessary for
74
+ open-source development. Features like time spent, priority, assignment of
75
+ tasks to developers, due dates, etc. are purposely relegated to the plugin
76
+ system.
60
77
 
61
- A ditz project consists of issues, releases and components.
78
+ A Ditz project consists of issues, releases and components.
62
79
 
63
80
  Issues:
64
- Issues are the fundamental currency of issue tracking. A ditz issue is either
65
- a feature or a bug, but this distinction doesn't affect anything other than
66
- how they're displayed.
81
+ Issues are the fundamental currency of issue tracking. A Ditz issue is either
82
+ a feature or a bug, but this distinction currently doesn't affect anything
83
+ other than how they're displayed.
67
84
 
68
85
  Each issue belongs to exactly one component, and is part of zero or one
69
86
  releases.
@@ -73,9 +90,13 @@ Issues:
73
90
  developers, present and future. Issue ids are typically not exposed to the
74
91
  user.
75
92
 
76
- Issues also have a non-exportable name, which is short and human-readable.
77
- All ditz commands use issue names instead of issue ids. Issue ids may change
78
- in certain circumstances, specifically after a "ditz drop" command.
93
+ Issues also have a non-global, non-exportable name, which is short and
94
+ human-readable. All Ditz commands use issue names in addition to issue ids.
95
+ Issue names (but not issue ids) may change in certain circumstances, e.g.
96
+ after a "ditz drop" command.
97
+
98
+ Issue names can be specified in comments, titles and descriptions, and Ditz
99
+ will automatically rewrite them as necessary when they change.
79
100
 
80
101
  Components:
81
102
  There is always one "general" component, named after the project itself. In
@@ -83,20 +104,14 @@ Components:
83
104
  with the question of which component to assign an issue to.
84
105
 
85
106
  Components simply provide a way of organizing issues, and have no real
86
- functionality. Issues are assigned names derived form the component they're
87
- assigned to.
107
+ functionality. Issues names are derived from the component they're assigned
108
+ to.
88
109
 
89
110
  Releases:
90
111
  A release is the primary grouping mechanism for issues. Status commands like
91
112
  "ditz status" and "ditz todo" always group issues by release. When a release
92
- is 100% complete, it can be marked as released, in which case the associated
93
- issues will cease appearing in ditz status and todo messages.
94
-
95
- == FUTURE WORK
96
-
97
- In future releases, Ditz will have a plugin architecture to allow tighter
98
- integration with specific SCMs and developer communication channels. (See
99
- http://ditz.rubyforge.org/ditz/issue-0704dafe4aef96279364013aba177a0971d425cb.html)
113
+ is 100% complete, it can be marked as released, and its issues will cease
114
+ appearing in Ditz status and todo messages.
100
115
 
101
116
  == LEARNING MORE
102
117
 
@@ -105,7 +120,7 @@ http://ditz.rubyforge.org/ditz/issue-0704dafe4aef96279364013aba177a0971d425cb.ht
105
120
 
106
121
  == REQUIREMENTS
107
122
 
108
- * trollop >= 1.8.2
123
+ * trollop >= 1.8.2, if running via RubyGems.
109
124
 
110
125
  == INSTALLATION
111
126
 
data/Rakefile CHANGED
@@ -17,10 +17,10 @@ Hoe.new('ditz', Ditz::VERSION) do |p|
17
17
  p.url = "http://ditz.rubyforge.org"
18
18
  p.changes = p.paragraphs_of('Changelog', 0..0).join("\n\n")
19
19
  p.email = "wmorgan-ditz@masanjin.net"
20
- p.extra_deps = [['trollop', '>= 1.8.2']]
20
+ p.extra_deps = [['trollop', '>= 1.9']]
21
21
  end
22
22
 
23
- WWW_FILES = FileList["www/*"] + %w(README.txt)
23
+ WWW_FILES = FileList["www/*"] + %w(README.txt PLUGINS.txt)
24
24
 
25
25
  task :upload_webpage => WWW_FILES do |t|
26
26
  sh "rsync -essh -cavz #{t.prerequisites * ' '} wmorgan@rubyforge.org:/var/www/gforge-projects/ditz/"
@@ -31,4 +31,36 @@ task :upload_report do |t|
31
31
  sh "rsync -essh -cavz ditz wmorgan@rubyforge.org:/var/www/gforge-projects/ditz/"
32
32
  end
33
33
 
34
+ task :plugins do |t|
35
+ sh "ruby -w ./make-plugins.txt.rb > PLUGINS.txt"
36
+ end
37
+
38
+ task :really_check_manifest do |t|
39
+ f1 = Tempfile.new "manifest"; f1.close
40
+ f2 = Tempfile.new "manifest"; f2.close
41
+ sh "git ls-files | egrep -v \"^bugs/\" | sort > #{f1.path}"
42
+ sh "sort Manifest.txt > #{f2.path}"
43
+
44
+ f3 = Tempfile.new "manifest"; f3.close
45
+ sh "diff -u #{f1.path} #{f2.path} > #{f3.path}; /bin/true"
46
+
47
+ left, right = [], []
48
+ IO.foreach(f3.path) do |l|
49
+ case l
50
+ when /^\-\-\-/
51
+ when /^\+\+\+/
52
+ when /^\-(.*)\n$/; left << $1
53
+ when /^\+(.*)\n$/; right << $2
54
+ end
55
+ end
56
+
57
+ puts
58
+ puts "Tracked by git but not in Manifest.txt:"
59
+ puts left.empty? ? " <nothing>" : left.map { |l| " " + l }
60
+
61
+ puts
62
+ puts "In Manifest.txt, but not tracked by git:"
63
+ puts right.empty? ? " <nothing>" : right.map { |l| " " + l }
64
+ end
65
+
34
66
  # vim: syntax=ruby
@@ -1,3 +1,9 @@
1
+ 0.5
2
+ ---
3
+
4
+ Two new plugins: git-sync, for synchronized git usage, and issue-claiming,
5
+ which allows you to claim issues for yourself. See PLUGINS.txt for details.
6
+
1
7
  0.4
2
8
  ---
3
9
  - Command-line completion scripts are now included for bash and zsh. To
data/bin/ditz CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/ruby1.8
2
2
 
3
3
  ## requires are split in two for efficiency reasons: ditz should be really
4
4
  ## fast when using it for completion.
@@ -11,13 +11,16 @@ if ARGV.include? '--commands'
11
11
  exit 0
12
12
  end
13
13
 
14
- require 'rubygems'
14
+ begin
15
+ require 'rubygems'
16
+ rescue LoadError
17
+ end
18
+
15
19
  require 'fileutils'
16
20
  require 'pathname'
17
21
  require 'trollop'; include Trollop
18
22
  require "ditz"
19
23
 
20
- PROJECT_FN = "project.yaml"
21
24
  CONFIG_FN = ".ditz-config"
22
25
  PLUGIN_FN = ".ditz-plugins"
23
26
 
@@ -30,9 +33,10 @@ $opts = options do
30
33
  opt :config_file, "Configuration file", :default => File.join(config_dir || ".", CONFIG_FN)
31
34
  opt :plugins_file, "Plugins file", :default => File.join(plugin_dir || ".", PLUGIN_FN)
32
35
  opt :verbose, "Verbose output", :default => false
33
- opt :no_comment, "Skip asking for a comment", :default => false
34
36
  opt :list_hooks, "List all hooks and descriptions, and quit.", :short => 'l', :default => false
37
+ stop_on_unknown
35
38
  end
39
+ $verbose = true if $opts[:verbose]
36
40
 
37
41
  Ditz::HookManager.register :startup, <<EOS
38
42
  Executes at startup
@@ -73,18 +77,10 @@ if $opts[:list_hooks]
73
77
  exit 0
74
78
  end
75
79
 
76
- plugins = begin
77
- Ditz::debug "loading plugins from #{$opts[:plugins_file]}"
78
- YAML::load_file$opts[:plugins_file]
80
+ begin
81
+ Ditz::load_plugins $opts[:plugins_file]
79
82
  rescue SystemCallError => e
80
83
  Ditz::debug "can't load plugins file: #{e.message}"
81
- []
82
- end
83
-
84
- plugins.each do |p|
85
- fn = Ditz::find_ditz_file "plugins/#{p}.rb"
86
- Ditz::debug "loading plugin #{p.inspect} from #{fn}"
87
- load fn
88
84
  end
89
85
 
90
86
  config = begin
@@ -105,14 +101,17 @@ EOS
105
101
  end
106
102
  end
107
103
 
108
- cmd = ARGV.shift || "todo"
109
104
  issue_dir = Pathname.new(config.issue_dir || $opts[:issue_dir])
105
+ cmd = ARGV.shift || "todo"
106
+ unless op.has_operation? cmd
107
+ die "no such command: #{cmd}"
108
+ end
110
109
 
111
110
  case cmd # some special commands not handled by Ditz::Operator
112
111
  when "init"
113
112
  die "#{issue_dir} directory already exists" if issue_dir.exist?
114
113
  issue_dir.mkdir
115
- fn = issue_dir + PROJECT_FN
114
+ fn = issue_dir + Ditz::FileStorage::PROJECT_FN
116
115
  project = op.init
117
116
  project.save! fn
118
117
  puts "Ok, #{issue_dir} directory created successfully."
@@ -122,89 +121,67 @@ when "help"
122
121
  exit
123
122
  end
124
123
 
125
- project_root = Ditz::find_dir_containing(issue_dir + PROJECT_FN)
126
- die "No #{issue_dir} directory---use 'ditz init' to initialize" unless project_root
127
- project_root += issue_dir
124
+ $project_root = Ditz::find_dir_containing(issue_dir + Ditz::FileStorage::PROJECT_FN)
125
+ die "No #{issue_dir} directory---use 'ditz init' to initialize" unless $project_root
126
+ $project_root += issue_dir
128
127
 
128
+ storage = Ditz::FileStorage.new $project_root
129
129
  project = begin
130
- fn = project_root + PROJECT_FN
131
- Ditz::debug "loading project from #{fn}"
132
- project = Ditz::Project.from fn
133
-
134
- fn = project_root + "issue-*.yaml"
135
- Ditz::debug "loading issues from #{fn}"
136
- project.issues = Dir[fn].map { |fn| Ditz::Issue.from fn }
137
- Ditz::debug "found #{project.issues.size} issues"
138
- project
130
+ storage.load
139
131
  rescue SystemCallError, Ditz::Project::Error => e
140
132
  die "#{e.message} (use 'init' to initialize)"
141
133
  end
142
134
 
143
- project.validate!
144
- project.issues.each { |p| p.project = project}
145
- project.assign_issue_names!
146
-
147
- unless op.has_operation? cmd
148
- die "no such command: #{cmd}"
149
- end
150
-
151
135
  Ditz::HookManager.run :startup, project, config
152
136
 
153
- ## talk about the law of unintended consequences. 'gets' requires this.
154
- args = []
155
- args << ARGV.shift until ARGV.empty?
156
-
157
137
  Ditz::debug "executing command #{cmd}"
158
138
  begin
159
- op.do cmd, project, config, args
160
- rescue Ditz::Operator::Error => e
161
- die e.message
139
+ op.do cmd, project, config, ARGV
140
+ rescue Ditz::Operator::Error, Ditz::Release::Error, Ditz::Project::Error, Ditz::Issue::Error => e
141
+ $stderr.puts "Error: #{e.message}"
142
+ exit(-1)
162
143
  rescue Errno::EPIPE, Interrupt
163
144
  puts
164
145
  exit 1
165
146
  end
166
147
 
167
- ## save project.yaml
168
- dirty = project.each_modelobject { |o| break true if o.changed? } || false
169
- if dirty
170
- fn = project_root + PROJECT_FN
171
- Ditz::debug "project is dirty, saving #{fn}"
172
- project.save! fn
173
- end
174
-
175
- ## project issues are not model fields proper, so they must be
176
- ## saved independently.
177
148
  changed_issues = project.issues.select { |i| i.changed? }
178
- changed_issues.each do |i|
179
- i.pathname ||= (project_root + "issue-#{i.id}.yaml")
180
- i.project ||= project # hack: not set on new issues
181
- Ditz::debug "issue #{i.name} is dirty, saving #{i.pathname}"
182
- i.save! i.pathname
183
- end
149
+ changed_not_added_issues = changed_issues - project.added_issues
184
150
 
185
- project.deleted_issues.each do |i|
186
- fn = i.pathname
187
- Ditz::debug "issue #{i.name} has been deleted, deleting #{fn}"
188
- FileUtils.rm fn
189
- end
151
+ storage.save project
152
+
153
+ ## at this point, for compatibility with older hook stuff, we set the pathname
154
+ ## directly on the issues.
190
155
 
156
+ project.issues.each { |i| i.pathname = storage.filename_for_issue(i) }
191
157
  unless project.added_issues.empty?
192
158
  unless Ditz::HookManager.run :after_add, project, config, project.added_issues
193
159
  puts "You may have to inform your SCM that the following files have been added:"
194
- project.added_issues.each { |i| puts " " + i.pathname }
160
+ project.added_issues.each { |i| puts " " + storage.filename_for_issue(i) }
195
161
  end
196
162
  end
197
163
 
198
164
  unless project.deleted_issues.empty?
199
165
  unless Ditz::HookManager.run :after_delete, project, config, project.deleted_issues
200
166
  puts "You may have to inform your SCM that the following files have been deleted:"
201
- project.deleted_issues.each { |i| puts " " + i.pathname }
167
+ project.deleted_issues.each { |i| puts " " + storage.filename_for_issue(i) }
202
168
  end
203
169
  end
204
170
 
205
- changed_not_added_issues = changed_issues - project.added_issues
206
171
  unless changed_not_added_issues.empty?
207
- Ditz::HookManager.run :after_update, project, config, changed_not_added_issues
172
+ unless Ditz::HookManager.run :after_update, project, config, changed_not_added_issues
173
+ puts "You may have to inform your SCM that the following files have been modified:"
174
+ changed_not_added_issues.each { |i| puts " " + storage.filename_for_issue(i) }
175
+ end
176
+ end
177
+
178
+ ## hack upon a hack
179
+ if project.changed?
180
+ project.pathname = storage.filename_for_project
181
+ unless Ditz::HookManager.run :after_update, project, config, [project]
182
+ puts "You may have to inform your SCM that the following files have been modified:"
183
+ puts " " + storage.filename_for_project
184
+ end
208
185
  end
209
186
 
210
187
  config.save! $opts[:config_file] if config.changed?