Tracker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2006 Hugh Bien
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,18 @@
1
+ == Using tracker (or whatever it's named)
2
+ tracker help
3
+ Can be used with alternative file, use the -f option.
4
+ tracker -f /path/to/sqlite3_file
5
+
6
+ == Dependencies
7
+ Ruby 1.8
8
+ SWIG
9
+ SQLite3
10
+ SQLite3-Ruby interface
11
+
12
+ == To add a new action
13
+ * Implement it in Bug class (for whatever bug needs that doesn't have)
14
+ * Add the command to the factory in lib/factory.rb
15
+ * Make sure the options are valid. You can add new options in the hash in tracker.rb.
16
+
17
+ == LICENSE
18
+ See MIT-LICENSE.
data/bin/fixture.rb ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "yaml"
4
+ require "rubygems"
5
+ require_gem "activerecord"
6
+
7
+ # Load the fixtures file and database
8
+ fixtures_file = ARGV[0] || "tests/fixtures.yml"
9
+ database = ARGV[1] || ".tracker_db"
10
+
11
+ # Load the YAML information
12
+ yaml = YAML.load_file(fixtures_file)
13
+
14
+ # Connect to the database file
15
+ ActiveRecord::Base.establish_connection(
16
+ :adapter => "sqlite3",
17
+ :database => database
18
+ )
19
+
20
+ class Bug < ActiveRecord::Base
21
+ end
22
+
23
+ class BugDescription < ActiveRecord::Base
24
+ end
25
+
26
+ class String
27
+ def to_constant
28
+ return Bug if self == "Bug"
29
+ return BugDescription if self == "BugDescription"
30
+ end
31
+ end
32
+
33
+ yaml.each_pair do |key, value|
34
+ key.to_constant.create( value )
35
+ end
36
+
37
+
data/bin/package ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+
3
+ cd lib
4
+ cat *.rb >> final_package
5
+ mv final_package ..
6
+ cd ..
7
+ cat tracker >> final_package
8
+ sed -e 's/^require.*$//g' final_package > temp
9
+ rm final_package
10
+ cat lib/requires temp > final_package
11
+ rm temp
12
+ chmod a+x final_package
data/bin/trac ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ # Tracker is under the MIT-LICENSE
3
+ # Please see http://ieng6.ucsd.edu/~hbien/tracker for more information about Tracker.
4
+
5
+ # Handles connection to the database
6
+
7
+ require "rubygems"
8
+ require_gem "Tracker"
9
+
10
+ # The default database file_name
11
+ DEFAULT_DATABASE_FILE_NAME = ".tracker_db"
12
+
13
+ # -----------------------------------------------------------------------------
14
+ # Begin executing the script here.
15
+ # -----------------------------------------------------------------------------
16
+
17
+ # What file should we use for the database?
18
+ database = DEFAULT_DATABASE_FILE_NAME
19
+
20
+ # What to do if no database can be found
21
+ def no_database_error(database_file = "the current")
22
+ puts "Could not find '.tracker_db' in #{database_file} or any parent directories."
23
+ puts "Try '#{File.basename(__FILE__)} create' to create a new database in the current directory or '#{File.basename(__FILE__)} help' to see available commands."
24
+ exit
25
+ end
26
+
27
+ # Is the user creating a new database?
28
+ if ARGV.include?("create")
29
+ if File.exists?(database)
30
+ puts "A '.tracker_db' database already exists in the current directory. Try removing it to create a new one."
31
+ exit
32
+ else
33
+ Database::create_database(database)
34
+ exit
35
+ end
36
+ end
37
+
38
+ # Find the database in parent directories
39
+ iteration = 0
40
+ while !File.exists?(database) && iteration < 10
41
+ iteration += 1
42
+ database = File.join("..", database)
43
+ end
44
+
45
+ # Could we find the database?
46
+ if iteration == 10 && !ARGV.include?("help") && !ARGV.include?("--file") && !ARGV.include?("-f")
47
+ no_database_error
48
+ else
49
+ if ARGV.include?("-f") || ARGV.include?("--file")
50
+ index = ARGV.index("-f") + 1 if ARGV.include?("-f")
51
+ index = ARGV.index("--file") + 1 if ARGV.include?("--file")
52
+ database = ARGV[index]
53
+ database = File.join(database, ".tracker_db") if File.directory?(database)
54
+ no_database_error(database) if !File.exist?(database)
55
+ end
56
+ # if we did, execute command
57
+ Database::connect_to_database(database)
58
+ parser = Interface.new
59
+ begin
60
+ parser.parse_command(ARGV)
61
+ rescue Exception => error
62
+ puts "Error executing database instructions: " + error
63
+ end
64
+ end
65
+
data/db/migrate ADDED
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require_gem "activerecord"
5
+
6
+ puts "Removing the database..."
7
+ `rm .tracker_db` if File.exists?(".tracker_db")
8
+
9
+ # Connect to the database
10
+ ActiveRecord::Base.establish_connection(
11
+ :adapter => "sqlite3",
12
+ :database => ".tracker_db"
13
+ )
14
+
15
+ # Create the bugs table
16
+ ActiveRecord::Schema.define do
17
+ create_table "bugs" do |t|
18
+ t.column "name", :string
19
+ t.column "priority", :int
20
+ t.column "area", :string
21
+ t.column "status", :boolean, :default => false
22
+ t.column "date_time", :date_time
23
+ end
24
+ end
25
+
26
+ # Creates the bug_descriptions
27
+ ActiveRecord::Schema.define do
28
+ create_table "bug_descriptions" do |t|
29
+ t.column "bug_id", :int
30
+ t.column "date_time", :date_time
31
+ t.column "description", :text
32
+ end
33
+ end
34
+
35
+ class Bug < ActiveRecord::Base
36
+ has_many :bug_descriptions
37
+ end
38
+
39
+ class BugDescription < ActiveRecord::Base
40
+ belongs_to :bugs
41
+ end
42
+
43
+ puts "Populating database with test data..."
44
+ yesterday = 1.day.ago.to_s(:db)
45
+ today = Time.now.to_s(:db)
46
+ tomorrow = 1.day.from_now.to_s(:db)
47
+
48
+ # Add test data to the database
49
+ bug = Bug.create(:name => "First", :priority => 1, :area => "One", :date_time => yesterday, :status => true)
50
+ bug.bug_descriptions.create(:date_time => yesterday, :description => "First description.\n")
51
+ bug.bug_descriptions.create(:date_time => today, :description => "Second description.\n")
52
+ bug.bug_descriptions.create(:date_time => today, :description => "Third description.\n")
53
+
54
+ bug = Bug.create(:name => "Second", :priority => 2, :area => "Two", :date_time => today, :status => true)
55
+ bug.bug_descriptions.create(:date_time => yesterday, :description => "First description.\n")
56
+ bug.bug_descriptions.create(:date_time => today, :description => "Second description.\n")
57
+ bug.bug_descriptions.create(:date_time => today, :description => "Third description.\n")
58
+
59
+ bug = Bug.create(:name => "Third", :priority => 3, :area => "Three", :date_time => tomorrow)
60
+ bug.bug_descriptions.create(:date_time => yesterday, :description => "First description.\n")
61
+ bug.bug_descriptions.create(:date_time => today, :description => "Second description.\n")
62
+ bug.bug_descriptions.create(:date_time => today, :description => "Third description.\n")
63
+
64
+ bug = Bug.create(:name => "Fourth", :priority => 4, :area => "Four", :date_time => tomorrow)
65
+ bug.bug_descriptions.create(:date_time => yesterday, :description => "First description.\n")
66
+ bug.bug_descriptions.create(:date_time => today, :description => "Second description.\n")
67
+ bug.bug_descriptions.create(:date_time => today, :description => "Third description.\n")
68
+
69
+
70
+
data/lib/action.rb ADDED
@@ -0,0 +1,79 @@
1
+ require File.dirname(__FILE__) + "/bug.rb"
2
+ require File.dirname(__FILE__) + "/helper.rb"
3
+
4
+ # The Action module is just a simple interface for the Bug class. Use this instead of using the Bug class directly, it should satisfy all actions needed to CRUD from the bugs database.
5
+ module Action
6
+ # Adds a new description to an existing bug. Used when a user wants to add new information found about a bug. Takes a hash as parameter where one item is either :name or :id and the other is :description
7
+ def self.append_description(hash)
8
+ return nil if hash[:description] =~ /^\s*$/ # Returns nil if no description given
9
+ bug = Bug.search(hash)
10
+ bug.bug_descriptions.create(:description => hash[:description])
11
+ end
12
+
13
+ # Closes the bug from being listed.
14
+ def self.close_bug(hash)
15
+ bug = Bug.search(hash)
16
+ bug.update_attributes(:status => true)
17
+ end
18
+
19
+ # Delets the bug with the given id/name and associated bug descriptions
20
+ def self.delete_bug(hash)
21
+ bug = Bug.search(hash)
22
+ bug.destroy
23
+ end
24
+
25
+ # Lists all of the open bugs by whatever conditions are meant
26
+ # The intersection of the conditions are returned
27
+ # By default, status is false
28
+ def self.list_bugs(hash = Hash.new)
29
+ hash[:status] = false unless hash.has_key?(:status)
30
+ bugs = Bug.find(:all, :conditions => Helper::hash_to_sql(hash), :order => "priority DESC, date_time")
31
+ return bugs
32
+ end
33
+
34
+ # Takes a hash as a parameter which is the data for the bug.
35
+ # * name - Descriptive name used for searching
36
+ # * priority - an integer, 1 being the highest priority, as large a number as you want.
37
+ # * area - Area, can be the filename, classname, or programmer name, etc.
38
+ # * description - Quick description, what was expected, what actually happened, and how to reproduce the bug.
39
+ def self.new_bug(hash)
40
+ description = hash[:description]
41
+ hash.delete(:description)
42
+ bug = Bug.create(hash)
43
+ bug.bug_descriptions.create(:description => description)
44
+ return bug
45
+ end
46
+
47
+ # Opens a bug to be listed.
48
+ def self.open_bug(hash)
49
+ bug = Bug.search(hash)
50
+ bug.update_attributes(:status => false)
51
+ end
52
+
53
+ # Updates the given bug with new information
54
+ def self.update_bug(hash)
55
+ bug = Bug.search(hash)
56
+ bug.update_attributes(hash)
57
+ end
58
+
59
+ # Returns all of the areas for the open bugs
60
+ def self.list_areas(*args)
61
+ # Find all open bugs
62
+ bugs = list_bugs(*args)
63
+
64
+ # Get all of the unique areas from the bugs
65
+ areas = bugs.collect { |bug| bug.area }
66
+ return areas.uniq
67
+ end
68
+
69
+ # Returns all of the names of the open bugs
70
+ def self.list_names(*args)
71
+ # Find all open bugs
72
+ bugs = list_bugs(*args)
73
+
74
+ # Get all of the uniqe names from the bugs
75
+ names = bugs.collect { |bug| bug.name }
76
+ return names.uniq
77
+ end
78
+ end
79
+
data/lib/bug.rb ADDED
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require_gem 'activerecord'
3
+
4
+ # Fields are name (string), priority (int), area (string), status (boolean).
5
+ class Bug < ActiveRecord::Base
6
+ has_many :bug_descriptions, :exclusively_dependent => true
7
+ before_create :save_date_time
8
+ before_update :save_date_time
9
+
10
+ # Is the bug open?
11
+ def open?
12
+ !status
13
+ end
14
+
15
+ # Is the bug closed?
16
+ def closed?
17
+ status
18
+ end
19
+
20
+ # Searches for a bug with given name or id
21
+ def self.search(term=nil)
22
+ # Get the needed search term if the argument is a hash
23
+ term = self.get_term(term) if term.kind_of?(Hash)
24
+
25
+ # Find the right bug
26
+ bug = self.get_bug_from_id_or_name(term)
27
+
28
+ # What to do if the bug isn't found
29
+ if bug == nil
30
+ raise Exception, "Bug not found with name '#{term}'." if term.kind_of?(String)
31
+ raise Exception, "Bug not found with id \##{term}." if term.kind_of?(Fixnum)
32
+ end
33
+
34
+ # Return the bug
35
+ return bug
36
+ end
37
+
38
+ private
39
+ # Makes sure the time is saved whenever a bug is saved or modified
40
+ def save_date_time
41
+ self.date_time = Time.now.to_s(:db)
42
+ end
43
+
44
+ # Gets the term (name or id) out of a hash
45
+ def self.get_term(hash)
46
+ term = hash[:name] if hash.has_key?(:name)
47
+ term = hash[:id] if hash.has_key?(:id)
48
+ return term
49
+ end
50
+
51
+ # Get the bug when given an id or name
52
+ def self.get_bug_from_id_or_name(search_key)
53
+ if search_key.kind_of?(String)
54
+ bug = find_by_name(search_key)
55
+ elsif search_key.kind_of?(Fixnum)
56
+ bug = find_by_id(search_key)
57
+ end
58
+ return bug
59
+ end
60
+
61
+ alias_method :opened?, :open?
62
+
63
+ end
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require_gem 'activerecord'
3
+
4
+ # Fields are bug_id (int), date (date), description (text).
5
+ class BugDescription < ActiveRecord::Base
6
+ belongs_to :bug
7
+ before_save :save_date_time
8
+ before_update :save_date_time
9
+
10
+ private
11
+ # Saves date_time as current time
12
+ def save_date_time
13
+ self.date_time = Time.now.to_s(:db)
14
+ end
15
+ end
data/lib/database.rb ADDED
@@ -0,0 +1,44 @@
1
+ require "rubygems"
2
+ require_gem "activerecord"
3
+
4
+ # This module handles the connection to a database. There are only two methods, one to connect, one to create (connect_to_database and create_database, repsectively).
5
+ module Database
6
+
7
+ # This method should be called when starting the script to connect the program
8
+ # to the database.
9
+ def self.connect_to_database(database)
10
+ # Start the script by connecting to the sqlite3 datbase
11
+ ActiveRecord::Base.establish_connection(
12
+ :adapter => "sqlite3",
13
+ :database => database
14
+ )
15
+ end
16
+
17
+ # If no database currently exists, this method will create one using
18
+ # ActiveRecord's migrations
19
+ def self.create_database(database)
20
+ puts "Creating database '#{database}' in current directory..."
21
+ connect_to_database(database)
22
+
23
+ # Creates the bugs table
24
+ ActiveRecord::Schema.define do
25
+ create_table "bugs" do |t|
26
+ t.column "name", :string
27
+ t.column "priority", :int
28
+ t.column "area", :string
29
+ t.column "status", :boolean, :default => false
30
+ t.column "date_time", :datetime
31
+ end
32
+ end
33
+
34
+ # Creates the bug_descriptions
35
+ ActiveRecord::Schema.define do
36
+ create_table "bug_descriptions" do |t|
37
+ t.column "bug_id", :int
38
+ t.column "date_time", :datetime
39
+ t.column "description", :text
40
+ end
41
+ end
42
+ end
43
+
44
+ end
data/lib/helper.rb ADDED
@@ -0,0 +1,16 @@
1
+ # This module includes static methods that do not fall into cateogries. These are just helper methods for various algorithms throughout the source code.
2
+ module Helper
3
+
4
+ # Takes a hash and returns the conditions sql for an ActiveRecord find method
5
+ def self.hash_to_sql(hash)
6
+ conditions = Array.new
7
+ hash.each do |attribute, term|
8
+ conditions << "#{attribute} = ?"
9
+ end
10
+ sql_string = conditions.join(" and ")
11
+ sql = [sql_string]
12
+ hash.each { |attribute, term| sql << term }
13
+ return sql
14
+ end
15
+
16
+ end
data/lib/interface.rb ADDED
@@ -0,0 +1,161 @@
1
+ require File.dirname(__FILE__) + "/prompter.rb"
2
+ require File.dirname(__FILE__) + "/database.rb"
3
+ require File.dirname(__FILE__) + "/action.rb"
4
+ require File.dirname(__FILE__) + "/bug.rb"
5
+ require File.dirname(__FILE__) + "/bug_description.rb"
6
+
7
+ # The Interface's job is to act as the interface between the user and the Action module. The Interface will make sure that messages are outputted to the user and pass along actions to the Action module depending on whatever the command is.
8
+ class Interface
9
+
10
+ # Let the tracker interface have access to the bugger - controller
11
+ def initialize()
12
+ @filename = File.basename(__FILE__)
13
+ @all_options = ["name", "priority", "area", "description"]
14
+ end
15
+
16
+ # Parses ARGV and executes the correct bugger operations
17
+ # Will print out to the user whatever the user requested
18
+ def parse_command(command_line_arguments)
19
+ # Parse the command
20
+ hash = args_to_hash(command_line_arguments)
21
+ command = command_line_arguments[0]
22
+ if command_line_arguments.size > 1 && command_line_arguments[1][0,1] != "-"
23
+ get_name_or_id(command_line_arguments[1], hash)
24
+ end
25
+
26
+ # Perform the correct action for whatever command it is
27
+ if command.include?("append") # Appends a description to existing bug
28
+ hash = include_name_or_id(hash)
29
+ hash[:description] = Prompter.description? if !hash.has_key?(:description)
30
+ Action::append_description(hash)
31
+ elsif command.include?("areas")
32
+ puts "Searched ticket areas are:"
33
+ Action::list_areas(hash).each { |area| puts " * " + area }
34
+ elsif command.include?("names")
35
+ puts "Searched ticket names are:"
36
+ Action::list_names(hash).each { |name| puts " * " + name }
37
+ elsif command.include?("close") # Closes an existing bug
38
+ hash = include_name_or_id(hash)
39
+ Action::close_bug(hash)
40
+ elsif command.include?("delete") # Deletes the bug from the database
41
+ hash = include_name_or_id(hash)
42
+ Action::delete_bug(hash)
43
+ elsif command.include?("list") # Lists either all open bugs or bugs by conditions
44
+ bugs = Action::list_bugs(hash)
45
+ puts bugs.collect { |bug| get_print_info(bug) }.join("\n") if bugs.size > 0
46
+ elsif command.include?("new") # Creates a new bug
47
+ set_options(@all_options, hash)
48
+ Action::new_bug(hash)
49
+ elsif command.include?("open") # Opens a closed bug
50
+ hash = include_name_or_id(hash)
51
+ Action::open_bug(hash)
52
+ elsif command.include?("update")
53
+ hash = include_name_or_id(hash)
54
+ Action::update_bug(hash)
55
+ elsif command.include?("help") || command.include?("--help") # Prints usage
56
+ print_usage
57
+ else
58
+ puts "Try '#{@filename} help'."
59
+ end
60
+ end
61
+
62
+
63
+ private
64
+ # Changes ARGV into a hash, ie. trac --name NAME --priority 2 becomes {:name => "NAME", :priority => 2}
65
+ def args_to_hash(args)
66
+ hash = Hash.new
67
+ hash[:id] = args[args.index("--id") + 1].to_i if args.include?("--id")
68
+ hash[:id] = args[args.index("-i") + 1].to_i if args.include?("-i")
69
+ hash[:name] = args[args.index("--name") + 1] if args.include?("--name")
70
+ hash[:name] = args[args.index("-n") + 1] if args.include?("-n")
71
+ hash[:priority] = args[args.index("--priority") + 1].to_i if args.include?("--priority")
72
+ hash[:priority] = args[args.index("-p") + 1].to_i if args.include?("-p")
73
+ hash[:area] = args[args.index("--area") + 1] if args.include?("--area")
74
+ hash[:area] = args[args.index("-a") + 1] if args.include?("-a")
75
+ hash[:description] = args[args.index("--description") + 1] if args.include?("--description")
76
+ hash[:description] = args[args.index("-d") + 1] if args.include?("-d")
77
+ hash[:status] = false if args.include?("--open") or args.include?("-o")
78
+ hash[:status] = true if args.include?("--closed") or args.include?("-c")
79
+ return hash
80
+ end
81
+
82
+ # Inspects the hash 'given' to see if it has the 'needed' keys. If it doesn't,
83
+ # will prompt the user for items.
84
+ def set_options(needed, given)
85
+ needed.each do |item|
86
+ if !given.has_key?(item.to_sym)
87
+ given[item.to_sym] = Prompter.send(item+"?")
88
+ end
89
+ end
90
+ return given
91
+ end
92
+
93
+ # If the given hash doesn't include an :id or :name key, prompts the user for
94
+ # an :id key and inserts it into the hash
95
+ def include_name_or_id(hash)
96
+ return hash if hash.has_key?(:name) or hash.has_key?(:id)
97
+ hash[:id] = Prompter.id?
98
+ return hash
99
+ end
100
+
101
+ # Determines if a given argument is an id or name and includes it in a hash as
102
+ # long as no other id or name was already included in the hash
103
+ def get_name_or_id(name_or_id, hash = Hash.new)
104
+ hash[:id] = name_or_id.to_i if name_or_id.to_i.kind_of?(Fixnum) && !hash.has_key?(:name) && name_or_id.to_i != 0
105
+ hash[:name] = name_or_id if name_or_id.kind_of?(String) && !hash.has_key?(:id)
106
+ return hash
107
+ end
108
+
109
+ # Returns the info for a bug to be printed out to the user
110
+ def get_print_info(bug)
111
+ working_string = String.new
112
+ working_string << "Ticket(#{bug.id}): #{bug.name}\n" if bug.id < 10
113
+ working_string << "Ticket(#{bug.id}): #{bug.name}\n" if bug.id >= 10 && bug.id < 100
114
+ working_string << "Ticket(#{bug.id}): #{bug.name}\n" if bug.id >= 100
115
+ working_string << "Priority: #{bug.priority}\n"
116
+ working_string << "Area: #{bug.area}\n"
117
+ working_string << "Description - #{bug.date_time.to_s(:short)}:\n"
118
+ descriptions = bug.bug_descriptions.collect { |desc| " * " + desc.description }.join
119
+ working_string << descriptions
120
+ return working_string
121
+ end
122
+
123
+ # Prints a description out
124
+ def print_description(description)
125
+ puts description.description # The description method
126
+ puts "-"
127
+ end
128
+
129
+ # Tracker's usage
130
+ def print_usage
131
+ puts "usage: #{@filename} <command> [options] [-f DIRECTORY | DATABASE]"
132
+ puts ""
133
+ puts "Available commands:"
134
+ puts " create"
135
+ puts " append [-i ID | -n NAME | -d DESCRIPTION]"
136
+ puts " close [-i ID | -n NAME]"
137
+ puts " delete [-i ID | -n NAME]"
138
+ puts " list [-i ID | -n NAME | -p PRIORITY | -a AREA | -c | -o]"
139
+ puts " help"
140
+ puts " new [-n NAME | -p PRIORITY | -a AREA | -d DESCRIPTION]"
141
+ puts " open [-i ID | -n NAME]"
142
+ puts " update [-i ID | -n NAME | -p PRIORITY | -a AREA]"
143
+ puts " areas [-n NAME | -p PRIORITY | -c | -o]"
144
+ puts " names [-a AREA | -p PRIORITY | -c | -o]"
145
+ puts ""
146
+ puts "Available options:"
147
+ puts " -i ID | --id ID"
148
+ puts " -n NAME | --name NAME"
149
+ puts " -p PRIORITY | --priority PRIORITY"
150
+ puts " -a AREA | --area AREA"
151
+ puts " -d DESCRIPTION | --description DESCRIPTION"
152
+ puts " -c | --closed"
153
+ puts " -o | --open"
154
+ puts " -f FILE | --file FILE"
155
+ puts ""
156
+ puts "Tracker is a command-line client for a bugs/features database. The database is kept in a flat file '.tracker_db' in the current directory."
157
+ puts ""
158
+ puts "To create a '.tracker_db' file, try using '#{@filename} create'."
159
+ end
160
+
161
+ end
data/lib/prompter.rb ADDED
@@ -0,0 +1,66 @@
1
+ # Prompts the user for information. All prompts are contained into this class. All methods are class methods.
2
+ class Prompter
3
+
4
+ # Asks for id
5
+ def self.id?
6
+ self.int("id")
7
+ end
8
+
9
+ # Asks for area
10
+ def self.area?
11
+ self.string("area")
12
+ end
13
+
14
+ # Ask for priority - int
15
+ def self.priority?
16
+ self.int("priority")
17
+ end
18
+
19
+ # Asks for a name
20
+ def self.name?
21
+ self.string("name")
22
+ end
23
+
24
+ # Asks for description. Terminate with ^d on empty line.
25
+ def self.description?
26
+ self.text("description")
27
+ end
28
+
29
+ private
30
+ # Prompt for a string
31
+ def self.string(term)
32
+ print term.capitalize + ": "
33
+ STDIN.gets.gsub("\n", "")
34
+ end
35
+
36
+ # Prompt for an int
37
+ def self.int(term)
38
+ print term.capitalize + ": "
39
+ STDIN.gets.to_i
40
+ end
41
+
42
+ # Prompt for text. Terminate with ^d on empty line.
43
+ def self.text(term)
44
+ # Create the method
45
+ puts term.capitalize + ":"
46
+ text = String.new
47
+ string = STDIN.gets
48
+ while string
49
+ text += string
50
+ string = STDIN.gets
51
+ end
52
+ return text
53
+ end
54
+
55
+ # Prompt for a yes or no.
56
+ def self.boolean(term)
57
+ print term.capitalize + ": "
58
+ string = STDIN.gets
59
+ if string.include?("Y") || string.include?("y")
60
+ return true
61
+ else
62
+ return false
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,3 @@
1
+ Bug:
2
+ name: Test
3
+
@@ -0,0 +1,135 @@
1
+ require "test/unit"
2
+
3
+ require File.dirname(__FILE__) + "/../lib/action.rb"
4
+ require File.dirname(__FILE__) + "/../lib/database.rb"
5
+ require File.dirname(__FILE__) + "/../lib/bug_description.rb"
6
+
7
+ class TestBugger < Test::Unit::TestCase
8
+ def setup
9
+ Database::connect_to_database(".tracker_db")
10
+ @bug_names = ["First", "Second", "Third", "Fourth"]
11
+ @bug_ids = [1, 2, 3, 4]
12
+ @bug_priorities = [1, 2, 3, 4]
13
+ @bug_areas = ["One", "Two", "Three", "Four"]
14
+ @bug_status = [true, true, false, false]
15
+ @descriptions = ["First description", "Second description", "Third description"]
16
+ end
17
+
18
+ def teardown
19
+ # Delete all bugs that aren't in the migration
20
+ bugs = Bug.find(:all)
21
+ bugs.delete_if { |bug| @bug_ids.include?(bug.id) }
22
+ bugs.each { |bug| bug.destroy }
23
+ end
24
+
25
+ def test_append_description
26
+ bug = Bug.create(:name => "test_append_description", :priority => 1, :area => "none")
27
+ Action::append_description(:id => bug.id, :description => "Hello")
28
+ Action::append_description(:name => "test_append_description", :description => "World")
29
+ assert_equal(bug.bug_descriptions[0].description, "Hello")
30
+ assert_equal(bug.bug_descriptions[1].description, "World")
31
+ end
32
+
33
+ # An empty description should NOT be appened.
34
+ def test_append_description_that_is_empty
35
+ bug = Bug.create(:name => "test_append_empty_description", :priority => 1, :area => "none")
36
+ descriptions_to_test = ["", " ", " ", "\n", "\n\n", " \n ", "\n ", " \n"]
37
+ descriptions_to_test.each do |string|
38
+ Action::append_description(:name => "test_append_empty_description", :description => string)
39
+ end
40
+ bug = Bug.find(bug.id)
41
+ assert_equal(0, bug.bug_descriptions.size)
42
+ end
43
+
44
+ def test_close_bug
45
+ bug = Bug.find_by_status(false)
46
+ Action::close_bug(:id => bug.id)
47
+ bug = Bug.find_by_id(bug.id)
48
+ assert(bug.closed?)
49
+ bug.status = false
50
+ bug.save
51
+ end
52
+
53
+ def test_delete_bug
54
+ bug = Bug.create(:name => "test_delete_bug", :priority => 2, :area => "none")
55
+ Action::delete_bug(:name => "test_delete_bug")
56
+ assert(!Bug.find_by_name("test_delete_bug"))
57
+ end
58
+
59
+ def test_list_bugs
60
+ bugs = Action::list_bugs
61
+ bugs.each { |bug| assert(@bug_names.include?(bug.name)) }
62
+ bugs = Action::list_bugs(:name => "First")
63
+ assert_equal(0, bugs.size)
64
+ bugs = Action::list_bugs(:status => false)
65
+ assert_equal(2, bugs.size)
66
+ end
67
+
68
+ # Make sure the listed bugs with a condition are ALL opened
69
+ def test_open_list_bugs
70
+ first = Bug.create(:name => "Another open bug", :area => "Four")
71
+ second = Bug.create(:name => "Another closed bug", :area => "Four", :status => true)
72
+ bugs = Action::list_bugs(:area => "Four")
73
+ bugs.each { |bug| assert(bug.open?) }
74
+ end
75
+
76
+ def test_new_bug
77
+ bug = Action::new_bug(:name => "test_new_bug", :priority => 1, :area => "none", :description => "This is a test description")
78
+ assert(bug)
79
+ assert(Bug.find_by_name("test_new_bug"))
80
+ assert_equal(Bug.find_by_name("test_new_bug").name, "test_new_bug")
81
+ assert_equal(bug.bug_descriptions[0].description, "This is a test description")
82
+ end
83
+
84
+ def test_open_bug
85
+ bug = Bug.find_by_status(true)
86
+ Action::open_bug(:id => bug.id)
87
+ bug = Bug.find_by_id(bug.id)
88
+ assert(bug.open?)
89
+ bug.status = true
90
+ bug.save
91
+ end
92
+
93
+ def test_update_bug
94
+ bug = Bug.create(:name => "test_update_bug", :priority => 1, :area => "none")
95
+ assert(bug)
96
+ Action::update_bug(:id => bug.id, :name => "new_name", :priority => 2, :area => "Nothing")
97
+ bug = Bug.find_by_id(bug.id)
98
+ assert_equal("new_name", bug.name)
99
+ assert_equal("Nothing", bug.area)
100
+ assert_equal(2, bug.priority)
101
+ end
102
+
103
+ # Should list all _open_ areas
104
+ def test_list_areas
105
+ areas = Action::list_areas
106
+ known_areas = ["Four", "Three"]
107
+ areas.each { |area| assert(known_areas.include?(area)) }
108
+ end
109
+
110
+ # Should list all bug areas with the condition given
111
+ def test_list_areas_with_conditions
112
+ areas = Action::list_areas(:name => "Fourth")
113
+ assert_equal("Four", areas[0])
114
+ areas = Action::list_areas(:priority => 3)
115
+ assert_equal("Three", areas[0])
116
+ end
117
+
118
+ # Should list all _open_ bug names
119
+ def test_list_names
120
+ names = Action::list_names
121
+ known_names = ["Fourth", "Third"]
122
+ names.each { |name| assert(known_names.include?(name)) }
123
+ end
124
+
125
+ # Should list all _open_ bug names with the conditions given
126
+ def test_list_names_with_conditions
127
+ names = Action::list_names(:name => "Third")
128
+ assert_equal("Third", names[0])
129
+ names = Action::list_names(:priority => 2)
130
+ assert_equal(nil, names[0])
131
+ names = Action::list_names(:priority => 2, :status => true)
132
+ assert_equal("Second", names[0])
133
+ end
134
+
135
+ end
data/tests/tc_bug.rb ADDED
@@ -0,0 +1,65 @@
1
+ require "test/unit"
2
+
3
+ require File.dirname(__FILE__) + "/../lib/bug.rb"
4
+
5
+ class TestBug < Test::Unit::TestCase
6
+ def setup
7
+ Database::connect_to_database(".tracker_db")
8
+ @bug_names = ["First", "Second", "Third", "Fourth"]
9
+ @bug_ids = [1, 2, 3, 4]
10
+ @bug_priorities = [1, 2, 3, 4]
11
+ @bug_areas = ["One", "Two", "Three", "Four"]
12
+ @bug_status = [true, true, false, false]
13
+ @descriptions = ["First description", "Second description", "Third description"]
14
+ end
15
+
16
+ def teardown
17
+ end
18
+
19
+ def test_open?
20
+ bug = Bug.find_by_name("Third")
21
+ assert(bug.open?)
22
+ assert(!bug.closed?)
23
+ end
24
+
25
+ def test_closed?
26
+ bug = Bug.find_by_name("First")
27
+ assert(bug.closed?)
28
+ assert(!bug.open?)
29
+ end
30
+
31
+ def test_search_by_name
32
+ @bug_names.each do |name|
33
+ bug = Bug.search(name)
34
+ assert_equal(name, bug.name)
35
+ end
36
+ end
37
+
38
+ def test_search_by_id
39
+ 4.times do |i|
40
+ bug = Bug.search(@bug_ids[i])
41
+ assert_equal(@bug_names[i], bug.name)
42
+ end
43
+ end
44
+
45
+ def test_create_with_date_time
46
+ bug = Bug.create(:name => "New Bug!", :priority => 1, :area => "None")
47
+ assert(bug.date_time)
48
+ bug.destroy
49
+ end
50
+
51
+ def test_save_with_date_time
52
+ bug = Bug.new(:name => "Another new bug!", :priority => 2, :area => "None")
53
+ bug.save
54
+ assert(bug.date_time)
55
+ bug.destroy
56
+ end
57
+
58
+ def test_destroy
59
+ bug = Bug.create(:name => "test_destroy", :priority => 1, :area => "None")
60
+ id = bug.id
61
+ bug.destroy
62
+ assert_raise(ActiveRecord::RecordNotFound) { Bug.find(id) }
63
+ end
64
+
65
+ end
@@ -0,0 +1,32 @@
1
+ require "test/unit"
2
+
3
+ require File.dirname(__FILE__) + "/../lib/bug_description.rb"
4
+
5
+ class TestBugDescription < Test::Unit::TestCase
6
+ def setup
7
+ Database::connect_to_database(".tracker_db")
8
+ @bug_names = ["First", "Second", "Third", "Fourth"]
9
+ @bug_ids = [1, 2, 3, 4]
10
+ @bug_priorities = [1, 2, 3, 4]
11
+ @bug_areas = ["One", "Two", "Three", "Four"]
12
+ @bug_status = [true, true, false, false]
13
+ @descriptions = ["First description", "Second description", "Third description"]
14
+ end
15
+
16
+ def teardown
17
+
18
+ end
19
+
20
+ def test_create_with_date_time
21
+ description = BugDescription.create(:description => "A new description for the first bug.", :bug_id => 1)
22
+ assert(description.date_time)
23
+ description.destroy
24
+ end
25
+
26
+ def test_save_with_date_time
27
+ description = BugDescription.new(:description => "A new description for the second bug.", :bug_id => 2)
28
+ description.save
29
+ assert(description.date_time)
30
+ description.destroy
31
+ end
32
+ end
File without changes
@@ -0,0 +1,9 @@
1
+ require "test/unit"
2
+
3
+ require File.dirname(__FILE__) + "/../lib/interface.rb"
4
+
5
+ class TestInterface < Test::Unit::TestCase
6
+ def test_truth
7
+ assert(true, "Test truth.")
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Adds current directory - test - and the lib directory to current PATH
4
+ $:.unshift File.join(File.dirname(__FILE__))
5
+
6
+ # require needed library files
7
+ require 'test/unit'
8
+ require File.dirname(__FILE__) + "/../lib/database.rb"
9
+
10
+ # Run all tests
11
+ test_cases = `ls #{File.dirname(__FILE__)}`.split("\n").select{ |f| f =~ /tc.*\.rb/ }.each do |file|
12
+ require File.join(File.dirname(__FILE__), file)
13
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: Tracker
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2006-08-23 00:00:00 -07:00
8
+ summary: Command-line bug tracking database application.
9
+ require_paths:
10
+ - lib
11
+ email: bienhd@gmail.com
12
+ homepage: http://ieng6.ucsd.edu/~hbien/tracker
13
+ rubyforge_project:
14
+ description:
15
+ autorequire:
16
+ default_executable: trac
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - Hugh Bien
30
+ files:
31
+ - bin/fixture.rb
32
+ - bin/package
33
+ - bin/trac
34
+ - tests/fixtures.yml
35
+ - tests/tc_action.rb
36
+ - tests/tc_bug.rb
37
+ - tests/tc_bug_description.rb
38
+ - tests/tc_integration.rb
39
+ - tests/tc_interface.rb
40
+ - tests/ts_tracker.rb
41
+ - lib/action.rb
42
+ - lib/bug.rb
43
+ - lib/bug_description.rb
44
+ - lib/database.rb
45
+ - lib/helper.rb
46
+ - lib/interface.rb
47
+ - lib/prompter.rb
48
+ - db/migrate
49
+ - README
50
+ - MIT-LICENSE
51
+ test_files: []
52
+
53
+ rdoc_options: []
54
+
55
+ extra_rdoc_files:
56
+ - README
57
+ - MIT-LICENSE
58
+ executables:
59
+ - trac
60
+ extensions: []
61
+
62
+ requirements: []
63
+
64
+ dependencies:
65
+ - !ruby/object:Gem::Dependency
66
+ name: sqlite3-ruby
67
+ version_requirement:
68
+ version_requirements: !ruby/object:Gem::Version::Requirement
69
+ requirements:
70
+ - - ">"
71
+ - !ruby/object:Gem::Version
72
+ version: 0.0.0
73
+ version:
74
+ - !ruby/object:Gem::Dependency
75
+ name: activerecord
76
+ version_requirement:
77
+ version_requirements: !ruby/object:Gem::Version::Requirement
78
+ requirements:
79
+ - - ">"
80
+ - !ruby/object:Gem::Version
81
+ version: 0.0.0
82
+ version: