flurin-ticgit 0.3.7
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/bin/ti +10 -0
- data/bin/ticgitweb +517 -0
- data/lib/ticgit/base.rb +308 -0
- data/lib/ticgit/cli.rb +338 -0
- data/lib/ticgit/comment.rb +17 -0
- data/lib/ticgit/ticket.rb +224 -0
- data/lib/ticgit.rb +28 -0
- metadata +88 -0
@@ -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
|
+
|