summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock6
-rw-r--r--Gemfile.rails5.lock6
-rw-r--r--app/models/project_services/flowdock_service.rb2
-rw-r--r--lib/flowdock/git.rb96
-rw-r--r--lib/flowdock/git/builder.rb150
6 files changed, 250 insertions, 12 deletions
diff --git a/Gemfile b/Gemfile
index 6772abeb49d..590ed17508e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -210,7 +210,7 @@ gem 'hipchat', '~> 1.5.0'
gem 'jira-ruby', '~> 1.4'
# Flowdock integration
-gem 'gitlab-flowdock-git-hook', '~> 1.0.1'
+gem 'flowdock', '~> 0.7'
# Slack integration
gem 'slack-notifier', '~> 1.5.1'
diff --git a/Gemfile.lock b/Gemfile.lock
index bd95f417caa..e0c098c3d8d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -278,10 +278,6 @@ GEM
google-protobuf (~> 3.1)
grpc (~> 1.10)
github-markup (1.7.0)
- gitlab-flowdock-git-hook (1.0.1)
- flowdock (~> 0.7)
- gitlab-grit (>= 2.4.1)
- multi_json
gitlab-gollum-lib (4.2.7.5)
gemojione (~> 3.2)
github-markup (~> 1.6)
@@ -1009,6 +1005,7 @@ DEPENDENCIES
flipper (~> 0.13.0)
flipper-active_record (~> 0.13.0)
flipper-active_support_cache_store (~> 0.13.0)
+ flowdock (~> 0.7)
fog-aliyun (~> 0.2.0)
fog-aws (~> 2.0.1)
fog-core (~> 1.44)
@@ -1025,7 +1022,6 @@ DEPENDENCIES
gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.118.1)
github-markup (~> 1.7.0)
- gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2)
gitlab-markup (~> 1.6.4)
gitlab-sidekiq-fetcher
diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock
index 8aebf78924f..56db3b4c9de 100644
--- a/Gemfile.rails5.lock
+++ b/Gemfile.rails5.lock
@@ -281,10 +281,6 @@ GEM
google-protobuf (~> 3.1)
grpc (~> 1.10)
github-markup (1.7.0)
- gitlab-flowdock-git-hook (1.0.1)
- flowdock (~> 0.7)
- gitlab-grit (>= 2.4.1)
- multi_json
gitlab-gollum-lib (4.2.7.5)
gemojione (~> 3.2)
github-markup (~> 1.6)
@@ -1018,6 +1014,7 @@ DEPENDENCIES
flipper (~> 0.13.0)
flipper-active_record (~> 0.13.0)
flipper-active_support_cache_store (~> 0.13.0)
+ flowdock (~> 0.7)
fog-aliyun (~> 0.2.0)
fog-aws (~> 2.0.1)
fog-core (~> 1.44)
@@ -1034,7 +1031,6 @@ DEPENDENCIES
gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.118.1)
github-markup (~> 1.7.0)
- gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2)
gitlab-markup (~> 1.6.4)
gitlab-sidekiq-fetcher
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 2545df06f6b..365792f03c3 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "flowdock-git-hook"
+require 'flowdock/git'
# Flow dock depends on Grit to compute the number of commits between two given
# commits. To make this depend on Gitaly, a monkey patch is applied
diff --git a/lib/flowdock/git.rb b/lib/flowdock/git.rb
new file mode 100644
index 00000000000..43e729c27d7
--- /dev/null
+++ b/lib/flowdock/git.rb
@@ -0,0 +1,96 @@
+
+require "multi_json"
+require "cgi"
+require "flowdock"
+require "flowdock/git/builder"
+
+module Flowdock
+ class Git
+ class TokenError < StandardError; end
+
+ class << self
+ def post(ref, from, to, options = {})
+ Git.new(ref, from, to, options).post
+ end
+
+ def background_post(ref, from, to, options = {})
+ Git.new(ref, from, to, options).background_post
+ end
+ end
+
+ def initialize(ref, from, to, options = {})
+ @ref = ref
+ @from = from
+ @to = to
+ @options = options
+ @token = options[:token] || config["flowdock.token"] || raise(TokenError.new("Flowdock API token not found"))
+ @commit_url = options[:commit_url] || config["flowdock.commit-url-pattern"] || nil
+ @diff_url = options[:diff_url] || config["flowdock.diff-url-pattern"] || nil
+ @repo_url = options[:repo_url] || config["flowdock.repository-url"] || nil
+ @repo_name = options[:repo_name] || config["flowdock.repository-name"] || nil
+ @permanent_refs = options[:permanent_refs] ||
+ (config["flowdock.permanent-references"] || "refs/heads/master")
+ .split(",")
+ .map(&:strip)
+ .map {|exp| Regexp.new(exp) }
+ end
+
+ # Send git push notification to Flowdock
+ def post
+ messages.each do |message|
+ Flowdock::Client.new(flow_token: @token).post_to_thread(message)
+ end
+ end
+
+ # Create and post notification in background process. Avoid blocking the push notification.
+ def background_post
+ pid = Process.fork
+ if pid.nil?
+ Grit::Git.with_timeout(600) do
+ post
+ end
+ else
+ Process.detach(pid) # Parent
+ end
+ end
+
+ def repo
+ @repo ||= Grit::Repo.new(
+ @options[:repo] || Dir.pwd,
+ is_bare: @options[:is_bare] || false
+ )
+ end
+
+ private
+
+ def messages
+ Git::Builder.new(repo: @repo,
+ ref: @ref,
+ before: @from,
+ after: @to,
+ commit_url: @commit_url,
+ branch_url: @branch_url,
+ diff_url: @diff_url,
+ repo_url: @repo_url,
+ repo_name: @repo_name,
+ permanent_refs: @permanent_refs,
+ tags: tags
+ ).to_hashes
+ end
+
+ # Flowdock tags attached to the push notification
+ def tags
+ if @options[:tags]
+ @options[:tags]
+ else
+ config["flowdock.tags"].to_s.split(",").map(&:strip)
+ end.map do |t|
+ CGI.escape(t)
+ end
+ end
+
+ def config
+ @config ||= Grit::Config.new(repo)
+ end
+ end
+end
diff --git a/lib/flowdock/git/builder.rb b/lib/flowdock/git/builder.rb
new file mode 100644
index 00000000000..4aec6a86df1
--- /dev/null
+++ b/lib/flowdock/git/builder.rb
@@ -0,0 +1,150 @@
+require "grit"
+require 'cgi'
+require "securerandom"
+
+module Flowdock
+ class Git
+ class Commit
+ def initialize(external_thread_id, thread, tags, commit)
+ @commit = commit
+ @external_thread_id = external_thread_id
+ @thread = thread
+ @tags = tags
+ end
+
+ def to_hash
+ hash = {
+ external_thread_id: @external_thread_id,
+ event: "activity",
+ author: {
+ name: @commit[:author][:name],
+ email: @commit[:author][:email]
+ },
+ title: title,
+ thread: @thread,
+ body: body
+ }
+ hash[:tags] = @tags if @tags
+ encode(hash)
+ end
+
+ private
+
+ def encode(hash)
+ return hash unless "".respond_to? :encode
+ encode_as_utf8(hash)
+ end
+
+ # This only works on Ruby 1.9
+ def encode_as_utf8(obj)
+ if obj.is_a? Hash
+ obj.each_pair do |key, val|
+ encode_as_utf8(val)
+ end
+ elsif obj.is_a?(Array)
+ obj.each do |val|
+ encode_as_utf8(val)
+ end
+ elsif obj.is_a?(String) && obj.encoding != Encoding::UTF_8
+ if !obj.force_encoding("UTF-8").valid_encoding?
+ obj.force_encoding("ISO-8859-1").encode!(Encoding::UTF_8, :invalid => :replace, :undef => :replace)
+ end
+ end
+ end
+
+ def body
+ content = @commit[:message][first_line.size..-1]
+ content.strip! if content
+ "<pre>#{content}</pre>" unless content.empty?
+ end
+
+ def first_line
+ @first_line ||= (@commit[:message].split("\n")[0] || @commit[:message])
+ end
+
+ def title
+ commit_id = @commit[:id][0, 7]
+ if @commit[:url]
+ "<a href=\"#{@commit[:url]}\">#{commit_id}</a> #{message_title}"
+ else
+ "#{commit_id} #{message_title}"
+ end
+ end
+
+ def message_title
+ CGI.escape_html(first_line.strip)
+ end
+ end
+
+ # Class used to build Git payload
+ class Builder
+ def initialize(opts)
+ @repo = opts[:repo]
+ @ref = opts[:ref]
+ @before = opts[:before]
+ @after = opts[:after]
+ @opts = opts
+ end
+
+ def commits
+ @repo.commits_between(@before, @after).map do |commit|
+ {
+ url: if @opts[:commit_url] then @opts[:commit_url] % [commit.sha] end,
+ id: commit.sha,
+ message: commit.message,
+ author: {
+ name: commit.author.name,
+ email: commit.author.email
+ }
+ }
+ end
+ end
+
+ def ref_name
+ @ref.to_s.sub(/\Arefs\/(heads|tags)\//, '')
+ end
+
+ def to_hashes
+ commits.map do |commit|
+ Commit.new(external_thread_id, thread, @opts[:tags], commit).to_hash
+ end
+ end
+
+ private
+
+ def thread
+ @thread ||= {
+ title: thread_title,
+ external_url: @opts[:repo_url]
+ }
+ end
+
+ def permanent?
+ @permanent ||= @opts[:permanent_refs].select do |regex|
+ regex.match(@ref)
+ end.size > 0
+ end
+
+ def thread_title
+ action = if permanent?
+ "updated"
+ end
+ type = if @ref.match(%r(^refs/heads/))
+ "branch"
+ else
+ "tag"
+ end
+ [@opts[:repo_name], type, ref_name, action].compact.join(" ")
+ end
+
+ def external_thread_id
+ @external_thread_id ||=
+ if permanent?
+ SecureRandom.hex
+ else
+ @ref
+ end
+ end
+ end
+ end
+end