gitlab-fogbugz 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2008 John Reilly
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,105 @@
1
+ GitLab + Fogbugz
2
+ ===
3
+
4
+ This is a simple sinatra application that has three responsibilities:
5
+
6
+ * Receive and parse the JSON commit info from GitLab's post-receive hooks and send it to FogBugz
7
+ * Act as a "gateway" for viewing multiple SCM repositories in FogBugz
8
+ * Edit case history per the commit message's instructions.
9
+
10
+ Prerequisites
11
+ ---
12
+ Gems:
13
+
14
+ * sinatra
15
+ * json
16
+ * mocha (for running tests)
17
+
18
+ Optional:
19
+
20
+ * [Ragel](http://research.cs.queensu.ca/~thurston/ragel/): for generating the FogBugz message parser. If you install gitlab-fogbugz as a gem, you will *not* need to generate the message parser.
21
+ * [GraphViz](http://www.graphviz.org): for generating a graph of the Ragel generated state machine):
22
+
23
+ To Install and Run:
24
+ ---
25
+
26
+ # Install the prerequisite gems.
27
+ $ sudo gem install sinatra json
28
+
29
+ # You need Ragel locally to make this next command work.
30
+ # If you installed gitlab-fogbugz as a gem, you do NOT need to execute this step.
31
+ $ rake ragel:compile
32
+
33
+ # Copies the config file examples to ~/.gitlab-fogbugz/config.yml
34
+ $ gitlab-fogbugz
35
+
36
+ ...edit config.yml (see "configuration" section below)...
37
+
38
+ $ gitlab-fogbugz-server [-p port] [-e production]
39
+
40
+ # Send your developers here so they can authenticate with FogBugz.
41
+ # Each developer must login here before their commit messages
42
+ # will be sent to FogBugz.
43
+ $ http://<gitlab-fogbugz-address>:<port>/login
44
+
45
+ Configuration
46
+ ---
47
+
48
+ ### GitLab repositories:
49
+ Set up your repositories on GitLab to send a post-receive hook to the root url of this sinatra app. Be sure to include the port, if other than 80.
50
+
51
+ ### gitlab-fogbugz-server (this app):
52
+ The configuration file holds several variables that you'll need to edit.
53
+
54
+ * **fb\_submit\_url**: The url to the cvsSubmit.[php|asp] file on your FogBugz server.
55
+ * **fb\_main\_url**: The url to your FogBugz's installation.
56
+ * **curl**: The path to the curl binary. Curl is used to submit the commit to FogBugz.
57
+ * **repos**: A list of the SCM repositories that you're using. Each repo has two urls:
58
+ * *log_url*: The url to the commit log for a specific file
59
+ * *diff_url*: The url to the specific commit or revision.
60
+
61
+ Each repo name must match the the values that are in the *sRepo* field in FogBug's *CVS* table.
62
+
63
+ ### Authenticating:
64
+ Each developer must login to FogBugz through this app. Visit **/login** and follow the instructions. The act of logging in will create a tokens.yml file in the app's config directory, chmod'ed 0600. **Note**: gitlab-fogbugz-server expects the developer's E-Mail addresses to match in both GitLab and FogBugz.
65
+
66
+ ### FogBugz:
67
+ You'll need to do some configuration in FogBugz as well. As the FogBugz admin, edit your site settings, and in the source control urls for logs and diffs, enter:
68
+
69
+ * Logs: "http://thisapp:port/repo_url?type=log&repo=^REPO&file=^FILE&r1=^R1&r2=^R2"
70
+ * Diffs: "http://thisapp:port/repo_url?type=diff&repo=^REPO&file=^FILE&r1=^R1&r2=^R2"
71
+
72
+ The only difference between the two is the "type" parameter.
73
+
74
+ > I'm not a fan of Fog Creek's [suggested solution](http://www.fogcreek.com/FogBugz/KB/howto/MultipleRepositories-Mult.html) for multiple repositories, as it requires you to copy a new script into the FogBugz website directory. This seems fine, but (as is my understanding) you'll have to copy it over again and again with each FogBugz upgrade because the website directory gets recreated each time. That's why this script also acts as the SCM viewer "gateway."
75
+
76
+ **Note:** If you've been using FogBugz in the past with only a single repository, odds are your *sRepo* field is empty. Mine was. Be sure that all of the records in FogBugz's *CVS* table have a valid *sRepo* that matches up to a repo specified in the config file.
77
+
78
+ Other Notes
79
+ ---
80
+ (NOTE: This section currently does not apply: as of gitlab 2.6 the post-receive hook does not receive the fle names, [see the request at github](https://github.com/gitlabhq/gitlabhq/issues/747) ).
81
+
82
+ When parsing out the file names from gitlab commits, I've tacked on the branch that the file lives on. So in FogBugz you'll see files like "master/myfile.rb". This is simply because my team does the "release on a branch" thing (aka [Release Line](http://www.scmpatterns.com/book/pattern-summary.html)), and I like to see which branch certain bugs were fixed on. Feel free to modify this behavior.
83
+
84
+ Caveats
85
+ ---
86
+ (NOTE: This section currently does not apply: as of gitlab 2.6 the post-receive hook does not receive the fle names, [see the request at github](https://github.com/gitlabhq/gitlabhq/issues/747) ).
87
+
88
+ It's fairly obvious that FogBugz was written for a more traditional CVS/SVN SCM system in mind. As such, the commit list display doesn't really jive with git:
89
+
90
+ ![Messy Commits List in FogBugz](http://img.skitch.com/20080424-kb6kujbfd224436pqgnhgj33sk.jpg)
91
+
92
+ This is in FogBugz 6.1.23. I've got a [thread started](http://support.fogcreek.com/default.asp?fogbugz.4.24526.0) on their forum asking for this to be cleaned up a bit. We'll see if it gets better in future releases.
93
+
94
+ Thanks
95
+ ---
96
+ All praises go to John Reilly et al for their work on [github-fogbugz](https://github.com/johnreilly/github-fogbugz), I simply renamed and adjusted a few things to get it working with GitLab.
97
+
98
+ Major thanks to [François Beausoleil](http://github.com/francois) for turning this project into something much greater than I had dreamed of.
99
+
100
+ Inspired by [github-campfire](http://github.com/jnewland/github-campfire) by [jnewland](http://github.com/jnewland) and
101
+ [github-twitter](http://github.com/jnunemaker/github-twitter) by [jnunemaker](http://github.com/jnunemaker).
102
+
103
+ License
104
+ ---
105
+ MIT. See LICENSE file.
data/Rakefile ADDED
@@ -0,0 +1,83 @@
1
+ # encoding: utf-8
2
+ require "rubygems"
3
+ require "rake/testtask"
4
+ require "rake/gempackagetask"
5
+
6
+ GEM = "gitlab-fogbugz"
7
+ VERSION = "0.0.1"
8
+ AUTHOR = ["John Reilly", "François Beausoleil", "Markus Fischer"]
9
+ EMAIL = ["jr@trms.com", "francois@teksol.info", "markus@fischer.name"]
10
+ HOMEPAGE = "http://github.com/mfn/gitlab-fogbugz"
11
+ SUMMARY = "Fork of github-fogbugz, a gem that acts as the gateway between GitLab and Fogbugz."
12
+
13
+ spec = Gem::Specification.new do |s|
14
+ s.name = GEM
15
+ s.version = VERSION
16
+ s.platform = Gem::Platform::RUBY
17
+ s.has_rdoc = true
18
+ s.extra_rdoc_files = ["README.markdown", "LICENSE", "TODO"]
19
+ s.summary = SUMMARY
20
+ s.description = s.summary
21
+ s.authors = AUTHOR
22
+ s.email = EMAIL
23
+ s.homepage = HOMEPAGE
24
+ s.executables = ["gitlab-fogbugz-server", "gitlab-fogbugz"]
25
+
26
+ # Uncomment this to add a dependency
27
+ s.add_dependency "json", "~> 1.1.2"
28
+
29
+ s.require_path = "lib"
30
+
31
+ # Must reference lib/message_parser.rb explicitely, or it won't be automatically generated
32
+ s.files = %w(LICENSE README.markdown Rakefile TODO lib/message_parser.rb) + Dir.glob("{lib,test,config,samples,bin}/**/*")
33
+ end
34
+
35
+ Rake::GemPackageTask.new(spec) do |pkg|
36
+ pkg.gem_spec = spec
37
+ end
38
+
39
+ task :install => [:package] do
40
+ sh %{sudo gem install pkg/#{GEM}-#{VERSION}}
41
+ end
42
+
43
+ Rake::TestTask.new("test" => "lib/message_parser.rb") do |t|
44
+ t.libs << "test"
45
+ t.test_files = FileList["test/*_test.rb"]
46
+ t.verbose = true
47
+ end
48
+
49
+ task :default => :test
50
+
51
+ file "lib/message_parser.rb" => "lib/message_parser_machine.rb" do
52
+ sh "ragel -R lib/message_parser_machine.rb -o lib/message_parser.rb"
53
+ end
54
+
55
+ file "tmp/machine.dot" => "lib/message_parser_machine.rb" do
56
+ sh "ragel -V lib/message_parser_machine.rb -o tmp/machine.dot"
57
+ end
58
+
59
+ file "tmp/machine.png" => "tmp/machine.dot" do
60
+ sh "dot -Tpng tmp/machine.dot > tmp/machine.png"
61
+ end
62
+
63
+ namespace :ragel do
64
+ desc "Compile the Ragel state machine to executable Ruby code"
65
+ task :compile => "lib/message_parser.rb"
66
+
67
+ desc "Generate tmp/machine.png"
68
+ task :graph => "tmp/machine.png"
69
+
70
+ desc "Delete generated Ragel files"
71
+ task :clean do
72
+ rm_f "lib/message_parser.rb"
73
+ rm_f "tmp/machine.dot"
74
+ rm_f "tmp/machine.png"
75
+ end
76
+ end
77
+
78
+ task :ragel => %w(ragel:compile ragel:graph)
79
+
80
+ desc "Remove all generated files"
81
+ task :clean => "ragel:clean" do
82
+ rm_rf "pkg"
83
+ end
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/<%= name %>.rb
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ require "fileutils"
3
+
4
+ case ARGV.length
5
+ when 0
6
+ config_path = File.expand_path("~/.gitlab-fogbugz/")
7
+ when 1
8
+ config_path = File.expand_path(ARGV.shift)
9
+ else
10
+ puts "0 or 1 arguments expected, received #{ARGV.length}"
11
+ puts
12
+ puts "Usage:"
13
+ puts " #{$0} </path/to/config/dir>"
14
+ puts " defaults to ~/.gitlab-fogbugz"
15
+ exit 1
16
+ end
17
+
18
+ FileUtils.mkpath(config_path)
19
+ filename = config_path + "/config.yml"
20
+ if File.exists? filename
21
+ puts "You already have an existing configuration in '#{filename}', not overwriting."
22
+ else
23
+ puts "Writing configuration file to #{config_path}/config.yml"
24
+ FileUtils.cp(File.dirname(__FILE__) + "/../config/config.yml.example", config_path + "/config.yml")
25
+ puts "You now have to edit the configuration file and set the right values."
26
+ end
27
+ puts "Documentation is available in the config file itself."
@@ -0,0 +1,262 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'json'
4
+ require 'sinatra'
5
+ require 'yaml'
6
+ require 'cgi'
7
+ require 'fileutils'
8
+
9
+ $: << File.dirname(__FILE__) + "/../lib"
10
+ require 'fogbugz_service'
11
+ require 'fogbugz_listener'
12
+ require 'message_parser'
13
+
14
+ # Returns the path to the configuration file. It defaults to ~/.gitlab-fogbugz/config.yml
15
+ def config_path
16
+ @config_path ||= File.expand_path(ENV["CONFIG_PATH"] || "~/.gitlab-fogbugz/config.yml")
17
+ end
18
+
19
+ # Returns a Hash of configuration options read from +config_path+.
20
+ def config
21
+ return @config if @config
22
+ @config = File.file?(config_path) ? YAML.load_file(config_path) : Hash.new
23
+ end
24
+
25
+ def write_config
26
+ FileUtils.mkpath(File.dirname(config_path)) if File.directory?(File.dirname(config_path))
27
+ File.open(config_path, "w") {|io| io.write config.to_yaml}
28
+ end
29
+
30
+ # Returns the path to the tokens file. It defaults to ~/.gitlab-fogbugz/tokens.yml
31
+ def tokens_path
32
+ @tokens_path ||= File.expand_path(ENV["TOKENS_PATH"] || "~/.gitlab-fogbugz/tokens.yml")
33
+ end
34
+
35
+ # Returns a Hash of tokens read from +tokens_path+.
36
+ def tokens
37
+ return @tokens if @tokens
38
+ FileUtils.mkpath(File.dirname(tokens_path)) if File.directory?(File.dirname(tokens_path))
39
+ @tokens = File.file?(tokens_path) ? YAML.load_file(tokens_path) : Hash.new
40
+ end
41
+
42
+ def write_tokens
43
+ FileUtils.mkpath(File.dirname(tokens_path)) if File.directory?(File.dirname(tokens_path))
44
+ File.open(tokens_path, "w") {|io| io.write tokens.to_yaml}
45
+ end
46
+
47
+ # This sinatra app has a couple of endpoints:
48
+ # / This is where GitLab will send
49
+ # its post-receive hooks
50
+ #
51
+ # /repo_url This is where FogBugz will send
52
+ # you when you click on a commit link
53
+ #
54
+ # If you want this Sinatra app to read the commit messages
55
+ # to resolve/close issues automatically, you need to have
56
+ # each of your developers to visit this page:
57
+ #
58
+ # /login This is a simple form to tell gitlab-fogbugz
59
+ # about all of your developers. Each dev must
60
+ # authenticate once with this app, then the token
61
+ # is kept on the filesystem.
62
+
63
+ ##
64
+ # GitLab should send its post-receive hook here.
65
+ post '/' do
66
+ request.body.rewind
67
+ GitlabFogbugz.new(request.body.read)
68
+ end
69
+
70
+ AUTH_FORM = lambda {|fb_url, params|
71
+ <<-EOHTML
72
+ <h1>FogBugz Authentication</h1>
73
+ <p>This form will authenticate you to <strong>#{fb_url}</strong></p>
74
+ <form method="post" action="/authenticate">
75
+ <p><label for="email">Email:</label><br/>
76
+ <input name="email" size="40" value="#{params['email']}"/></p>
77
+ <p><label for="password">Password:</label><br/>
78
+ <input type="password" name="password" size="20"/></p>
79
+ <p><input type="submit" value="Authenticate to FogBugz"/></p>
80
+ </form>
81
+ EOHTML
82
+ }
83
+
84
+ get "/login" do
85
+ if fb_main_url = config['fb_main_url'] then
86
+ AUTH_FORM.call(fb_main_url, Hash.new)
87
+ else
88
+ "<h1>A configuration error exists</h1><p>Ooops, the configuration file does not exist at path: <strong><tt>#{config_path}</tt></strong>.</p>"
89
+ end
90
+ end
91
+
92
+ post "/authenticate" do
93
+ begin
94
+ service = FogbugzService.new(config["fb_main_url"], config["curl"])
95
+ service.connect do
96
+ token = service.logon(params["email"], params["password"])
97
+ tokens[params["email"]] = token
98
+ end
99
+
100
+ write_tokens
101
+ redirect "/authenticated"
102
+ rescue FogbugzService::BadCredentials
103
+ "<p>Failed authentication: <strong>#{$!.message}</strong></p>" + AUTH_FORM.call(config['fb_main_url'], params)
104
+ end
105
+ end
106
+
107
+ get "/authenticated" do
108
+ <<-HTML
109
+ <h1>Authenticated</h1>
110
+ <p>You are now authenticated to FogBugz. Go forth and commit!</p>
111
+
112
+ <h2>Writing commit messages</h2>
113
+ <p>Your commit messages can now contain text like the following to automatically manage your cases:</p>
114
+ <blockquote>
115
+ <p>Implemented foo, corrected baz.</p>
116
+ <p>Implements #1234, references #2345. Closes #1234.</p>
117
+ </blockquote>
118
+ <p>This would automatically add the commit message to cases #1234 <em>and</em> #2345. The commit message will be appended as an event to the case. In addition, case #1234 will be closed.</p>
119
+ <p>You can also mention multiple cases with one keyword, e.g. <tt>Implements #1234 and #5123</tt>.</p>
120
+ <p>GitlabFogbugz recognizes the following keywords (also singular versions of the same keywords):</p>
121
+ <ul>
122
+ <li><tt>bugzid:</tt><br>For "compatibility" with the subversion wrapper provided by Fogcreek; however you still need to prefix the case number with <tt>#</tt>. Works like <tt>references</tt>.</li>
123
+ <li><tt>closes</tt></li>
124
+ <li><tt>completes</tt></li>
125
+ <li><tt>fixes</tt></li>
126
+ <li><tt>implements</tt></li>
127
+ <li><tt>reopens</tt></li>
128
+ <li><tt>references</tt> or <tt>refs</tt><br>Does not change the state of the case, just adds the commit message to this case.</li>
129
+ <li><tt>resolves</tt><br>Resolves is different then <tt>closes</tt>, <tt>completes</tt>, <tt>fixes</tt> and <tt>implements</tt>: it does not explicitly sets the FogBugz case status, thus changes the case to it's categories default status for resolved cases: Bug -&gt; "fixed", Feature -&gt; "Implemented", Inquirt -&gt; "Responded" and Schedule Item -&gt; "Completed"</li>
130
+ </ul>
131
+ <p>NOTE: FogBugz does not allow closing a case that isn't resolved, so you really must use "Implements X, closes X", or else it won't work.</p>
132
+ <p>Back to <a href="/tokens">Authenticated users</a></p>
133
+ HTML
134
+ end
135
+
136
+ get "/tokens" do
137
+ response = []
138
+ response << "<h1>List of authenticated users</h1>"
139
+ response << "<ul>"
140
+ tokens.map do |email, token|
141
+ response << "<li>#{email}"
142
+ response << %Q(<form method="post" action="/remove"><input type="hidden" name="email" value="#{email}"/><input type="submit" value="Remove"/></form>)
143
+ response << "</li>"
144
+ end
145
+
146
+ response << "</ul>"
147
+ response << %Q(<p><a href="/login">Add a user</a></p>)
148
+ response.join("\n")
149
+ end
150
+
151
+ post "/remove" do
152
+ redirect "/tokens" unless params["email"]
153
+ tokens.delete(params["email"])
154
+ write_tokens
155
+ redirect "/tokens"
156
+ end
157
+
158
+ ##
159
+ # Set the log and diff urls (in fogbugz's site settings) to point here.
160
+ # Log url: http://localhost:4567/repo_url?type=log&repo=^REPO&file=^FILE&r1=^R1&r2=^R2
161
+ # Diff url: http://localhost:4567/repo_url?type=diff&repo=^REPO&file=^FILE&r1=^R1&r2=^R2
162
+ get '/repo_url' do
163
+ #pull out the repo's scm viewer url from the config file
164
+ if params[:type] == 'log'
165
+ url = config['repos'][params[:repo]]['log_url']
166
+ elsif params[:type] == 'diff'
167
+ url = config['repos'][params[:repo]]['diff_url']
168
+ else
169
+ "Unknown repo viewer type."
170
+ end
171
+
172
+ if url
173
+ url.gsub!(/\^REPO/, params[:repo])
174
+ url.gsub!(/\^FILE/, params[:file])
175
+ url.gsub!(/\^R1/, params[:r1])
176
+ url.gsub!(/\^R2/, params[:r2])
177
+ redirect url
178
+ end
179
+
180
+ end
181
+
182
+ error do
183
+ err = request.env['sinatra.error']
184
+ puts "Error handling request: #{err.name}"
185
+ puts err.backtrace.join("\n")
186
+ end
187
+
188
+
189
+ ##
190
+ # This class does all of the json parsing and submits a push's commits to fogbugz
191
+ class GitlabFogbugz
192
+
193
+ def initialize(payload)
194
+ payload = JSON.parse(payload)
195
+ return unless payload.keys.include?("repository")
196
+
197
+ repo = payload["repository"]["name"]
198
+ branch = payload["ref"].split('/').last
199
+
200
+ payload["commits"].each do |c|
201
+ process_commit(c["id"], c, repo, branch, payload['before'], config['fb_submit_url'], config['curl'])
202
+ end
203
+
204
+ rescue
205
+ puts "Oh noez, something went wrong: #{$!.message}"
206
+ puts $!.backtrace.join("\n")
207
+ raise
208
+ end
209
+
210
+ def submit_to_fogbugz(sha1, commit, token, curl_path)
211
+ listener = FogbugzListener.new(:commit_url => commit["url"], :message => commit["message"], :sha1 => sha1)
212
+ MessageParser.parse(commit["message"], listener)
213
+ service = FogbugzService.new(config["fb_main_url"], curl_path, token)
214
+ service.connect do
215
+ listener.update_fogbugz(service)
216
+ end
217
+ end
218
+
219
+ def process_commit(sha1, commit, repo, branch, before, fb_submit_url, curl_path)
220
+
221
+ # from each commit in the payload, we need to extract:
222
+ # - name of repo, renamed as "gitlab-<repo>"
223
+ # - name of file, including branch. e.g.: "4.7/Builds/Cablecast.fbp4"
224
+ # - sha1 of commit (R2)
225
+ # - sha1 of before (R1)
226
+ # - bugzid (found inside the commit message)
227
+
228
+ message = commit["message"]
229
+ author = commit["author"]["email"]
230
+
231
+ token = tokens[author]
232
+ submit_to_fogbugz(sha1, commit, token, curl_path) if token
233
+
234
+ files = commit["removed"] | commit["added"] | commit["modified"]
235
+ files = [] if !files
236
+
237
+ # look for a bug id in each line of the commit message
238
+ bug_list = []
239
+ message.split("\n").each do |line|
240
+ if (line =~ /\s*Bug[zs]*\s*IDs*\s*[#:; ]+((\d+[ ,:;#]*)+)/i)
241
+ bug_list << $1.to_i
242
+ end
243
+ end
244
+
245
+ # for each found bugzid, submit the files to fogbugz.
246
+ # this will set the sRepo to "gitlab-<repo>", which will be used above
247
+ # when fogbugz asks for the scm viewer url.
248
+ bug_list.each do |fb_bugzid|
249
+ files.each do |f|
250
+ fb_repo = CGI.escape("gitlab-#{repo}")
251
+ fb_r1 = CGI.escape("#{before}")
252
+ fb_r2 = CGI.escape("#{sha1}")
253
+ fb_file = CGI.escape("#{branch}/#{f}")
254
+
255
+ #build the GET request, and send it to fogbugz
256
+ fb_url = "#{fb_submit_url}?ixBug=#{fb_bugzid}&sRepo=#{fb_repo}&sFile=#{fb_file}&sPrev=#{fb_r1}&sNew=#{fb_r2}"
257
+ puts `#{curl_path} --insecure --silent --output /dev/null '#{fb_url}'`
258
+
259
+ end
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,24 @@
1
+ # GithubFogbugz configuration file
2
+ # ================================
3
+ #
4
+ # Setup your gitlab-fogbugz integration through this configuration file.
5
+ #
6
+ # The URL to the cvsSubmit.[php|asp] file on your server. This is to add the list of changed files to the cases.
7
+ fb_submit_url: "http://fogbugz.server.com/cvsSubmit.php"
8
+
9
+ # The URL to the root of your FogBugz installation.
10
+ fb_main_url: "http://fogbugz.server.com/"
11
+
12
+ # The path to the Curl binary. Curl is used because of issues with SSL in Ruby's libraries.
13
+ curl: "/usr/bin/curl"
14
+
15
+ # A list of repositories that are known to your FogBugz installation.
16
+ # Each repository is identified by a name and has 2 values: log_url and diff_url.
17
+ # The repository's name must match the value given in the sRepos field of your FogBugz installation.
18
+ #
19
+ # See the FogBugz section in README.markdown for the details of how to setup your urls.
20
+ # The examples below will get you started.
21
+ repos:
22
+ gitlab-project:
23
+ log_url: "https://gitlab/project/commits?path=^FILE"
24
+ diff_url: "https://gitlab/project/commits/^R2"
@@ -0,0 +1,64 @@
1
+ class FogbugzListener
2
+ attr_reader :options
3
+
4
+ def initialize(options={})
5
+ @options = options
6
+ @state = :invalid
7
+ @actions = Hash.new {|h, k| h[k] = Array.new}
8
+ end
9
+
10
+ def fix
11
+ @state = :fix
12
+ end
13
+
14
+ def implement
15
+ @state = :implement
16
+ end
17
+
18
+ def reopen
19
+ @state = :reopen
20
+ end
21
+
22
+ def close
23
+ @state = :close
24
+ end
25
+
26
+ def reference
27
+ @state = :reference
28
+ end
29
+
30
+ def complete
31
+ @state = :complete
32
+ end
33
+
34
+ def case(bugid)
35
+ @actions[@state] << bugid
36
+ end
37
+
38
+ def resolve
39
+ @state = :resolve
40
+ end
41
+
42
+ def update_fogbugz(service)
43
+ references = @actions.delete(:reference)
44
+
45
+ message_header = ""
46
+ message_header << "Commit: #{options[:sha1]}\n"
47
+ message_header << "#{options[:commit_url]}\n" if options[:commit_url]
48
+
49
+ message = message_header + "\n" + options[:message]
50
+
51
+ if @actions.empty? then
52
+ references.each do |bugid|
53
+ service.append_message(:case => bugid, :message => message)
54
+ end if references
55
+ else
56
+ message << "\n\nReferences " << references.map {|bugid| "case #{bugid}"}.join(", ") if references && !references.empty?
57
+ @actions.each_pair do |action, bugids|
58
+ bugids.each do |bugid|
59
+ service.send(action, :case => bugid, :message => message)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end