flurin-ticgit 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,224 @@
1
+ module TicGit
2
+ class Ticket
3
+
4
+ attr_reader :base, :opts
5
+ attr_accessor :ticket_id, :ticket_name
6
+ attr_accessor :title, :description, :state, :milestone, :assigned, :opened
7
+ attr_accessor :comments, :tags, :attachments # arrays
8
+
9
+ def initialize(base, options = {})
10
+ options[:user_name] ||= base.git.config('user.name')
11
+ options[:user_email] ||= base.git.config('user.email')
12
+
13
+ @base = base
14
+ @opts = options || {}
15
+
16
+ @description = options.delete(:description)
17
+ @state = 'open' # by default
18
+ @comments = []
19
+ @tags = []
20
+ @attachments = []
21
+ end
22
+
23
+ def self.create(base, title, options = {})
24
+ t = Ticket.new(base, options)
25
+ t.title = title
26
+ t.ticket_name = self.create_ticket_name(title)
27
+ t.save_new
28
+ t
29
+ end
30
+
31
+ def self.open(base, ticket_name, ticket_hash, options = {})
32
+ tid = nil
33
+
34
+ t = Ticket.new(base, options)
35
+ t.ticket_name = ticket_name
36
+
37
+ basic_title, date = self.parse_ticket_name(ticket_name)
38
+
39
+ # t.title will be overridden below if the file TICKET_TITLE exists
40
+ t.title = basic_title
41
+ t.opened = date
42
+
43
+ ticket_hash['files'].each do |fname, value|
44
+ if fname == 'TICKET_ID'
45
+ t.ticket_id = value
46
+ elsif fname == 'TICKET_TITLE'
47
+ t.title = base.git.gblob(value).contents rescue nil
48
+ elsif fname == 'TICKET_DESCRIPTION'
49
+ t.description = base.git.gblob(value).contents rescue nil
50
+ else
51
+ # matching
52
+ data = fname.split('_')
53
+ if data[0] == 'ASSIGNED'
54
+ t.assigned = data[1]
55
+ end
56
+ if data[0] == 'COMMENT'
57
+ t.comments << TicGit::Comment.new(base, fname, value)
58
+ end
59
+ if data[0] == 'TAG'
60
+ t.tags << data[1]
61
+ end
62
+ if data[0] == 'STATE'
63
+ t.state = data[1]
64
+ end
65
+ end
66
+ end
67
+
68
+
69
+ t
70
+ end
71
+
72
+
73
+ def self.parse_ticket_name(name)
74
+ unless name =~ /^([^_]+)_(.+)_([^_]+)$/
75
+ raise "invalid ticket name #{name.inspect}"
76
+ end
77
+ epoch, title, rand = $1, $2.gsub('-', ' '), $3
78
+ return [title, Time.at(epoch.to_i)]
79
+ end
80
+
81
+ # write this ticket to the git database
82
+ def save_new
83
+ base.in_branch do |wd|
84
+ base.logger.info "saving #{ticket_name}"
85
+
86
+ Dir.mkdir(ticket_name)
87
+ Dir.chdir(ticket_name) do
88
+ base.new_file('TICKET_ID', ticket_name)
89
+ base.new_file('ASSIGNED_' + email, email)
90
+ base.new_file('STATE_' + state, state)
91
+ base.new_file('TICKET_TITLE',self.title)
92
+ base.new_file('TICKET_DESCRIPTION',self.description) if self.description
93
+
94
+ # add initial comment
95
+ #COMMENT_080315060503045__schacon_at_gmail
96
+ base.new_file(comment_name(email), opts[:comment]) if opts[:comment]
97
+
98
+ # add initial tags
99
+ if opts[:tags] && opts[:tags].size > 0
100
+ opts[:tags] = opts[:tags].map { |t| t.strip }.compact
101
+ opts[:tags].each do |tag|
102
+ if tag.size > 0
103
+ tag_filename = 'TAG_' + Ticket.clean_string(tag)
104
+ if !File.exists?(tag_filename)
105
+ base.new_file(tag_filename, tag_filename)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ base.git.add
113
+ base.git.commit("added ticket #{ticket_name}")
114
+ end
115
+ # ticket_id
116
+ end
117
+
118
+ def self.clean_string(string)
119
+ string.downcase.gsub(/[^a-zA-Z0-9_:;,.]+/, '-')
120
+ end
121
+
122
+ def add_comment(comment)
123
+ return false if !comment
124
+ base.in_branch do |wd|
125
+ Dir.chdir(ticket_name) do
126
+ base.new_file(comment_name(email), comment)
127
+ end
128
+ base.git.add
129
+ base.git.commit("added comment to ticket #{ticket_name}")
130
+ end
131
+ end
132
+
133
+ def change_state(new_state)
134
+ return false if !new_state
135
+ return false if new_state == state
136
+
137
+ base.in_branch do |wd|
138
+ Dir.chdir(ticket_name) do
139
+ base.new_file('STATE_' + new_state, new_state)
140
+ end
141
+ base.git.remove(File.join(ticket_name,'STATE_' + state))
142
+ base.git.add
143
+ base.git.commit("added state (#{new_state}) to ticket #{ticket_name}")
144
+ end
145
+ end
146
+
147
+ def change_assigned(new_assigned)
148
+ new_assigned ||= email
149
+ return false if new_assigned == assigned
150
+
151
+ base.in_branch do |wd|
152
+ Dir.chdir(ticket_name) do
153
+ base.new_file('ASSIGNED_' + new_assigned, new_assigned)
154
+ end
155
+ base.git.remove(File.join(ticket_name,'ASSIGNED_' + assigned))
156
+ base.git.add
157
+ base.git.commit("assigned #{new_assigned} to ticket #{ticket_name}")
158
+ end
159
+ end
160
+
161
+ def add_tag(tag)
162
+ return false if !tag
163
+ added = false
164
+ tags = tag.split(',').map { |t| t.strip }
165
+ base.in_branch do |wd|
166
+ Dir.chdir(ticket_name) do
167
+ tags.each do |add_tag|
168
+ if add_tag.size > 0
169
+ tag_filename = 'TAG_' + Ticket.clean_string(add_tag)
170
+ if !File.exists?(tag_filename)
171
+ base.new_file(tag_filename, tag_filename)
172
+ added = true
173
+ end
174
+ end
175
+ end
176
+ end
177
+ if added
178
+ base.git.add
179
+ base.git.commit("added tags (#{tag}) to ticket #{ticket_name}")
180
+ end
181
+ end
182
+ end
183
+
184
+ def remove_tag(tag)
185
+ return false if !tag
186
+ removed = false
187
+ tags = tag.split(',').map { |t| t.strip }
188
+ base.in_branch do |wd|
189
+ tags.each do |add_tag|
190
+ tag_filename = File.join(ticket_name, 'TAG_' + Ticket.clean_string(add_tag))
191
+ if File.exists?(tag_filename)
192
+ base.git.remove(tag_filename)
193
+ removed = true
194
+ end
195
+ end
196
+ if removed
197
+ base.git.commit("removed tags (#{tag}) from ticket #{ticket_name}")
198
+ end
199
+ end
200
+ end
201
+
202
+ def path
203
+ File.join(state, ticket_name)
204
+ end
205
+
206
+ def comment_name(email)
207
+ 'COMMENT_' + Time.now.to_i.to_s + '_' + email
208
+ end
209
+
210
+ def email
211
+ opts[:user_email] || 'anon'
212
+ end
213
+
214
+ def assigned_name
215
+ assigned.split('@').first rescue ''
216
+ end
217
+
218
+ def self.create_ticket_name(title)
219
+ [Time.now.to_i.to_s, Ticket.clean_string(title), rand(999).to_i.to_s].join('_')
220
+ end
221
+
222
+
223
+ end
224
+ end
data/lib/ticgit.rb ADDED
@@ -0,0 +1,28 @@
1
+ # Add the directory containing this file to the start of the load path if it
2
+ # isn't there already.
3
+ $:.unshift(File.dirname(__FILE__)) unless
4
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
5
+
6
+ require 'rubygems'
7
+ # requires git >= 1.0.5
8
+ require 'git'
9
+ require 'ticgit/base'
10
+ require 'ticgit/ticket'
11
+ require 'ticgit/comment'
12
+
13
+ require 'ticgit/cli'
14
+
15
+ # TicGit Library
16
+ #
17
+ # This library implements a git based ticketing system in a git repo
18
+ #
19
+ # Author:: Scott Chacon (mailto:schacon@gmail.com)
20
+ # License:: MIT License
21
+ #
22
+ module TicGit
23
+ # options
24
+ # :logger => Logger.new(STDOUT)
25
+ def self.open(git_dir, options = {})
26
+ Base.new(git_dir, options)
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flurin-ticgit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.7
5
+ platform: ruby
6
+ authors:
7
+ - Scott Chacon
8
+ - "Mislav Marohni\xC4\x87"
9
+ - Flurin Egger
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2008-09-11 00:00:00 -07:00
15
+ default_executable:
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: schacon-git
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 1.0.5
25
+ version:
26
+ - !ruby/object:Gem::Dependency
27
+ name: sinatra
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.3.1
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: wycats-thor
37
+ version_requirement:
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ version: 0.9.5
43
+ version:
44
+ description:
45
+ email: schacon@gmail.com
46
+ executables:
47
+ - ti
48
+ - ticgitweb
49
+ extensions: []
50
+
51
+ extra_rdoc_files: []
52
+
53
+ files:
54
+ - lib/ticgit/base.rb
55
+ - lib/ticgit/cli.rb
56
+ - lib/ticgit/comment.rb
57
+ - lib/ticgit/ticket.rb
58
+ - lib/ticgit.rb
59
+ - bin/ti
60
+ - bin/ticgitweb
61
+ has_rdoc: false
62
+ homepage: http://github.com/schacon/ticgit/wikis
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.2.0
84
+ signing_key:
85
+ specification_version: 2
86
+ summary: A distributed ticketing system for Git projects.
87
+ test_files: []
88
+