parse the specs, and the commandline arguments, and resolve them. does typechecking but currently doesn't check for open_issues actually being open, unstarted_issues being unstarted, etc. probably will check for this in the future.
# File lib/operator.rb, line 32 def build_args project, method, args specs = @operations[method][:args_spec] command = "command '#{method_to_op method}'" if specs.empty? && args == ["<options>"] die_with_completions project, method, nil end built_args = specs.map do |spec| optional = spec.to_s =~ /^maybe_/ spec = spec.to_s.gsub(/^maybe_/, "").intern # :( val = args.shift case val when nil next if optional specname = spec.to_s.gsub("_", " ") article = specname =~ /^[aeiou]/ ? "an" : "a" raise Error, "#{command} requires #{article} #{specname}" when "<options>" die_with_completions project, method, spec end case spec when :issue, :open_issue, :unstarted_issue, :started_issue, :assigned_issue ## issue completion sticks the title on there, so this will strip it off valr = val.sub(/\A(\w+-\d+)_.*$/,'\1') issues = project.issues_for valr case issues.size when 0; raise Error, "no issue with name #{val.inspect}" when 1; issues.first else raise Error, "multiple issues matching name #{val.inspect}" end when :release, :unreleased_release if val == "unassigned" :unassigned else project.release_for(val) or raise Error, "no release with name #{val}" end when :component project.component_for(val) or raise Error, "no component with name #{val}" if val else val # no translation for other types end end raise Error, "too many arguments for #{command}" unless args.empty? built_args end
# File lib/operator.rb, line 23 def build_opts method, args options_blk = @operations[method][:options_blk] options_blk and options args, &options_blk or nil end
# File lib/operator.rb, line 21 def has_operation? op; @operations.member? op_to_method(op) end
# File lib/operator.rb, line 9 def method_to_op meth; meth.to_s.gsub("_", "-") end
# File lib/operator.rb, line 10 def op_to_method op; op.gsub("-", "_").intern end
# File lib/operator.rb, line 336 def actually_do_todo project, config, releases, full releases ||= project.unreleased_releases + [:unassigned] releases = [*releases] releases.each do |r| puts r == :unassigned ? "Unassigned:" : "#{r.name} (#{r.status}):" issues = project.issues_for_release r issues = issues.select { |i| i.open? } unless full puts(todo_list_for(issues.sort_by { |i| i.sort_order }) || "No open issues.") puts end end
# File lib/operator.rb, line 196 def add project, config, opts issue = Issue.create_interactively(:args => [config, project]) or return issue.log "created", config.user, get_comment(opts) project.add_issue issue project.assign_issue_names! puts "Added issue #{issue.name}." end
# File lib/operator.rb, line 223 def add_component project, config component = Component.create_interactively(:args => [project, config]) or return project.add_component component puts "Added component #{component.name}." end
# File lib/operator.rb, line 233 def add_reference project, config, opts, issue puts "Adding a reference to #{issue.name}: #{issue.title}." reference = ask "Reference" issue.add_reference reference issue.log "added reference #{issue.references.size}", config.user, get_comment(opts) puts "Added reference to #{issue.name}." end
# File lib/operator.rb, line 214 def add_release project, config, opts, maybe_name puts "Adding release #{maybe_name}." if maybe_name release = Release.create_interactively(:args => [project, config], :with => { :name => maybe_name }) or return release.log "created", config.user, get_comment(opts) project.add_release release puts "Added release #{release.name}." end
# File lib/operator.rb, line 554 def archive project, config, release, dir dir ||= "ditz-archive-#{release.name}" FileUtils.mkdir dir FileUtils.cp project.pathname, dir project.issues_for_release(release).each do |i| FileUtils.cp i.pathname, dir project.drop_issue i end puts "Archived to #{dir}." end
# File lib/operator.rb, line 388 def assign project, config, opts, issue, maybe_release if maybe_release && maybe_release.name == issue.release raise Error, "issue #{issue.name} already assigned to release #{issue.release}" end puts "Issue #{issue.name} currently " + if issue.release "assigned to release #{issue.release}." else "not assigned to any release." end release = maybe_release || begin releases = project.releases.sort_by { |r| (r.release_time || 0).to_i } releases -= [releases.find { |r| r.name == issue.release }] if issue.release ask_for_selection(releases, "release") do |r| r.name + if r.released? " (released #{r.release_time.pretty_date})" else " (unreleased)" end end end issue.assign_to_release release, config.user, get_comment(opts) puts "Assigned #{issue.name} to #{release.name}." end
# File lib/operator.rb, line 487 def changelog project, config, r puts "== #{r.name} / #{r.released? ? r.release_time.pretty_date : 'unreleased'}" project.group_issues(project.issues_for_release(r)).each do |type, issues| issues.select { |i| i.closed? }.each do |i| if type == :bugfix puts "* #{type}: #{i.title}" else puts "* #{i.title}" end end end end
# File lib/plugins/issue-claiming.rb, line 94 def claim project, config, opts, issue puts "Claiming issue #{issue.name}: #{issue.title}." comment = ask_multiline "Comments" unless $opts[:no_comment] issue.claim config.user, comment, opts[:force] puts "Issue #{issue.name} marked as claimed by #{config.user}" end
# File lib/plugins/issue-claiming.rb, line 132 def claimed project, config, opts, releases releases ||= project.unreleased_releases + [:unassigned] releases = [*releases] issues = project.issues.inject({}) do |h, i| r = project.release_for(i.release) || :unassigned if i.claimed? && (opts[:all] || i.open?) && releases.member?(r) (h[i.claimer] ||= []) << i end h end if issues.empty? puts "No issues." else issues.keys.sort.each do |c| puts "#{c}:" puts todo_list_for(issues[c], :show_release => true) puts end end end
# File lib/plugins/issue-claiming.rb, line 83 def close project, config, opts, issue if issue.claimed? && issue.claimer != config.user raise Error, "issue #{issue.name} claimed by #{issue.claimer}" else __issue_claiming_close project, config, opts, issue end end
# File lib/plugins/git.rb, line 129 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
# File lib/operator.rb, line 109 def do op, project, config, args meth = self.class.op_to_method(op) # Parse options, removing them from args opts = self.class.build_opts meth, args built_args = self.class.build_args project, meth, args built_args.unshift opts if opts send meth, project, config, *built_args end
# File lib/operator.rb, line 205 def drop project, config, issue project.drop_issue issue puts "Dropped #{issue.name}. Note that other issue names may have changed." end
# File lib/operator.rb, line 570 def edit project, config, opts, issue data = { :title => issue.title, :description => issue.desc, :reporter => issue.reporter } fn = run_editor { |f| f.puts data.to_yaml } unless fn puts "Aborted." return end begin edits = YAML.load_file fn comment = opts[:silent] ? nil : get_comment(opts) if issue.change edits, config.user, comment, opts[:silent] puts "Change recorded." else puts "No changes." end end end
# File lib/operator.rb, line 512 def grep project, config, match re = /#{match}/ issues = project.issues.select do |i| i.title =~ re || i.desc =~ re || i.log_events.map { |time, who, what, comments| comments }.join(" ") =~ re end puts(todo_list_for(issues) || "No matching issues.") end
# File lib/operator.rb, line 133 def help project, config, opts, command if opts[:cow] puts "MOO!" puts "All is well with the world now. A bit more methane though." return end return help_single(command) if command puts Ditz commands: ops = self.class.operations len = ops.map { |name, op| name.to_s.length }.max ops.each do |name, opts| printf " %#{len}s: %s\n", name, opts[:desc] end puts Use 'ditz help <command>' for details. end
# File lib/operator.rb, line 155 def help_single command name, opts = self.class.operations.find { |name, spec| name == command } raise Error, "no such ditz command '#{command}'" unless name args = opts[:args_spec].map do |spec| case spec.to_s when /^maybe_(.*)$/ "[#{$1}]" else "<#{spec.to_s}>" end end.join(" ") puts #{opts[:desc]}.Usage: ditz #{name} #{args} end
# File lib/operator.rb, line 501 def html project, config, dir dir ||= "html" HtmlView.new(project, config, dir).render_all end
# File lib/operator.rb, line 126 def init Project.create_interactively end
# File lib/operator.rb, line 522 def log project, config project.issues.map { |i| i.log_events.map { |e| [e, i] } }. flatten_one_level.sort_by { |e| e.first.first }.reverse. each do |(date, author, what, comment), i| puts date : #{date.localtime} (#{date.ago} ago)author: #{author} issue: [#{i.name}] #{i.title} #{what}#{comment.gsub(/^/, " > ") unless comment =~ /^\A\s*\z/} puts unless comment.blank? end end
# File lib/plugins/issue-claiming.rb, line 114 def mine project, config, opts, releases releases ||= project.unreleased_releases + [:unassigned] releases = [*releases] issues = project.issues.select do |i| r = project.release_for(i.release) || :unassigned releases.member?(r) && i.claimer == config.user && (opts[:all] || i.open?) end if issues.empty? puts "No issues." else print_todo_list_by_release_for project, issues end end
# File lib/operator.rb, line 313 def print_todo_list_by_release_for project, issues by_release = issues.inject({}) do |h, i| r = project.release_for(i.release) || :unassigned h[r] ||= [] h[r] << i h end (project.releases + [:unassigned]).each do |r| next unless by_release.member? r puts r == :unassigned ? "Unassigned:" : "#{r.name} (#{r.status}):" print todo_list_for(by_release[r]) puts end end
# File lib/operator.rb, line 186 def reconfigure project, config new_config = Config.create_interactively :defaults_from => config new_config.save! $opts[:config_file] puts "Configuration written." end
# File lib/operator.rb, line 481 def release project, config, opts, release release.release! project, config.user, get_comment(opts) puts "Release #{release.name} released!" end
# File lib/operator.rb, line 469 def releases project, config a, b = project.releases.partition { |r| r.released? } (b + a.sort_by { |r| r.release_time }).each do |r| status = r.released? ? "released #{r.release_time.pretty_date}" : r.status puts "#{r.name} (#{status})" end end
# File lib/plugins/git.rb, line 102 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
# File lib/operator.rb, line 418 def set_component project, config, opts, issue, maybe_component puts "Changing the component of issue #{issue.name}: #{issue.title}." if project.components.size == 1 raise Error, "this project does not use multiple components" end if maybe_component && maybe_component.name == issue.component raise Error, "issue #{issue.name} already assigned to component #{issue.component}" end component = maybe_component || begin components = project.components components -= [components.find { |r| r.name == issue.component }] if issue.component ask_for_selection(components, "component") { |r| r.name } end issue.assign_to_component component, config.user, get_comment(opts) oldname = issue.name project.assign_issue_names! puts Issue #{oldname} is now #{issue.name}. Note that the names of other issues mayhave changed as well. end
# File lib/operator.rb, line 539 def shortlog project, config project.issues.map { |i| i.log_events.map { |e| [e, i] } }. flatten_one_level.sort_by { |e| e.first.first }.reverse. each do |(date, author, what, comment), i| shortauthor = if author =~ /<(.*?)@/ $1 else author end[0..15] printf "%13s|%13s|%13s|%s\n", date.ago, i.name, shortauthor, what end end
# File lib/operator.rb, line 349 def show project, config, issue ScreenView.new(project, config).render_issue issue end
# File lib/plugins/issue-claiming.rb, line 65 def start project, config, opts, issue if issue.claimed? && issue.claimer != config.user raise Error, "issue #{issue.name} claimed by #{issue.claimer}" else __issue_claiming_start project, config, opts, issue end end
# File lib/operator.rb, line 242 def status project, config, releases releases ||= project.unreleased_releases + [:unassigned] if releases.empty? puts "No releases." return end entries = releases.map do |r| title, issues = (r == :unassigned ? r.to_s : r.name), project.issues_for_release(r) middle = Issue::TYPES.map do |type| type_issues = issues.select { |i| i.type == type } num = type_issues.size nc = type_issues.count_of { |i| i.closed? } pc = 100.0 * (type_issues.empty? ? 1.0 : nc.to_f / num) "%2d/%2d %s" % [nc, num, type.to_s.pluralize(num, false)] end bar = if r == :unassigned "" elsif r.released? "(released)" elsif issues.empty? "(no issues)" elsif issues.all? { |i| i.closed? } "(ready for release)" else status_bar_for(issues) end [title, middle, bar] end title_size = 0 middle_sizes = [] entries.each do |title, middle, bar| title_size = [title_size, title.length].max middle_sizes = middle.zip(middle_sizes).map do |e, s| [s || 0, e.length].max end end entries.each do |title, middle, bar| printf "%-#{title_size}s ", title middle.zip(middle_sizes).each_with_index do |(e, s), i| sep = i < middle.size - 1 ? "," : "" printf "%-#{s + sep.length}s ", e + sep end puts bar end end
# File lib/operator.rb, line 296 def status_bar_for issues Issue::STATUS_WIDGET. sort_by { |k, v| -Issue::STATUS_SORT_ORDER[k] }. map { |k, v| v * issues.count_of { |i| i.status == k } }. join end
# File lib/plugins/issue-claiming.rb, line 74 def stop project, config, opts, issue if issue.claimed? && issue.claimer != config.user raise Error, "issue #{issue.name} claimed by #{issue.claimer}" else __issue_claiming_stop project, config, opts, issue end end
# File lib/plugins/git-sync.rb, line 55 def sync project, config, opts unless config.git_sync_local_branch $stderr.puts "Please run ditz reconfigure and set the local and remote branch names" return end Dir.chdir $project_root puts "[in #{$project_root}]" sh "git add *.yaml", :force => true, :fake => opts[:dry_run] sh "git commit -m 'issue updates'", :force => true, :fake => opts[:dry_run] sh "git pull", :fake => opts[:dry_run] sh "git push #{config.git_sync_remote_repo} #{config.git_sync_local_branch}:#{config.git_sync_remote_branch}", :fake => opts[:dry_run] puts puts "Ditz issue state synchronized." end
# File lib/operator.rb, line 332 def todo project, config, opts, releases actually_do_todo project, config, releases, opts[:all] end
# File lib/operator.rb, line 303 def todo_list_for issues, opts={} return if issues.empty? name_len = issues.max_of { |i| i.name.length } issues.map do |i| s = sprintf "%s %#{name_len}s: %s", i.status_widget, i.name, i.title s += " [#{i.release}]" if opts[:show_release] && i.release s + "\n" end.join end
# File lib/operator.rb, line 447 def unassign project, config, opts, issue puts "Unassigning issue #{issue.name}: #{issue.title}." issue.unassign config.user, get_comment(opts) puts "Unassigned #{issue.name}." end
# File lib/plugins/issue-claiming.rb, line 104 def unclaim project, config, opts, issue puts "Unclaiming issue #{issue.name}: #{issue.title}." comment = ask_multiline "Comments" unless $opts[:no_comment] issue.unclaim config.user, comment, opts[:force] puts "Issue #{issue.name} marked as unclaimed." end
# File lib/plugins/issue-claiming.rb, line 158 def unclaimed project, config, opts, releases releases ||= project.unreleased_releases + [:unassigned] releases = [*releases] issues = project.issues.select do |i| r = project.release_for(i.release) || :unassigned releases.member?(r) && i.claimer.nil? && (opts[:all] || i.open?) end if issues.empty? puts "No issues." else print_todo_list_by_release_for project, issues end end
Generated with the Darkfish Rdoc Generator 2.