FEATURE: support multi repos

FEATURE: support multi repos

  • This also adds support for webhooks so events are way faster
From 5211cb65608637e3faf3da1b75e59748cf5d436a Mon Sep 17 00:00:00 2001
From: Sam <sam.saffron@gmail.com>
Date: Tue, 27 Nov 2018 12:42:24 +1100
Subject: [PATCH] FEATURE: support multi repos

- This also adds support for webhooks so events are way faster

diff --git a/app/controllers/discourse_code_review/code_review_controller.rb b/app/controllers/discourse_code_review/code_review_controller.rb
index a8f817d..5ca36b8 100644
--- a/app/controllers/discourse_code_review/code_review_controller.rb
+++ b/app/controllers/discourse_code_review/code_review_controller.rb
@@ -1,76 +1,124 @@
-class ::DiscourseCodeReview::CodeReviewController < ::ApplicationController
-  before_action :ensure_logged_in
-  before_action :ensure_staff
+# frozen_string_literal: true
 
-  def followup
-    topic = Topic.find_by(id: params[:topic_id])
+module DiscourseCodeReview
+  class CodeReviewController < ::ApplicationController
+    before_action :ensure_logged_in
+    before_action :ensure_staff
 
-    tags = topic.tags.pluck(:name)
+    skip_before_action :verify_authenticity_token, only: :webhook
+    skip_before_action :ensure_logged_in, only: :webhook
+    skip_before_action :ensure_staff, only: :webhook
+    skip_before_action :redirect_to_login_if_required, only: :webhook
+    skip_before_action :check_xhr, only: :webhook
 
-    tags -= [
-      SiteSetting.code_review_approved_tag,
-      SiteSetting.code_review_pending_tag
-    ]
+    def webhook
 
-    tags << SiteSetting.code_review_followup_tag
+      if SiteSetting.code_review_github_webhook_secret.blank?
+        Rails.logger.warn("Make sure you set a secret up in code_review_github_webhook_secret")
+        raise Discourse::InvalidAccess
+      end
 
-    DiscourseTagging.tag_topic_by_names(topic, Guardian.new(current_user), tags)
+      request.body.rewind
+      body = request.body.read
+      signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), SiteSetting.code_review_github_webhook_secret, body)
 
-    topic.add_moderator_post(
-      current_user,
-      nil,
-      bump: false,
-      post_type: Post.types[:small_action],
-      action_code: "followup"
-    )
+      if !Rack::Utils.secure_compare("sha1=#{signature}", request.env['HTTP_X_HUB_SIGNATURE'])
+        raise Discourse::InvalidAccess
+      end
 
-    render_next_topic(topic.category_id)
+      type = request.env['HTTP_X_GITHUB_EVENT']
 
-  end
+      # unique hash for webhook
+      # delivery = request.env['HTTP_X_GITHUB_DELIVERY']
 
-  def approve
+      repo = params["repository"]
+      repo_name = repo["full_name"] if repo
 
-    topic = Topic.find_by(id: params[:topic_id])
+      if ["commit_comment", "push"].include? type
+        client = DiscourseCodeReview.octokit_client
+        repo = GithubRepo.new(repo_name, client)
+        importer = Importer.new(repo)
 
-    tags = topic.tags.pluck(:name)
+        if type == "commit_comment"
+          importer.import_comments
+        elsif type == "push"
+          importer.import_commits
+        end
+      end
 
-    tags -= [
-      SiteSetting.code_review_followup_tag,
-      SiteSetting.code_review_pending_tag
-    ]
+      render plain: '"ok"'
+    end
 
-    tags << SiteSetting.code_review_approved_tag
+    def followup
+      topic = Topic.find_by(id: params[:topic_id])
 
-    DiscourseTagging.tag_topic_by_names(topic, Guardian.new(current_user), tags)
+      tags = topic.tags.pluck(:name)
 
-    topic.add_moderator_post(
-      current_user,
-      nil,
-      bump: false,
-      post_type: Post.types[:small_action],
-      action_code: "approved"
-    )
+      tags -= [
+        SiteSetting.code_review_approved_tag,
+        SiteSetting.code_review_pending_tag
+      ]
 
-    render_next_topic(topic.category_id)
+      tags << SiteSetting.code_review_followup_tag
 
-  end
+      DiscourseTagging.tag_topic_by_names(topic, Guardian.new(current_user), tags)
 
-  protected
+      topic.add_moderator_post(
+        current_user,
+        nil,
+        bump: false,
+        post_type: Post.types[:small_action],
+        action_code: "followup"
+      )
 
-  def render_next_topic(category_id)
-    next_topic = Topic
-      .joins(:tags)
-      .where('tags.name = ?', SiteSetting.code_review_pending_tag)
-      .where(category_id: category_id)
-      .where('user_id <> ?', current_user.id)
-      .order('bumped_at asc')
-      .first
+      render_next_topic(topic.category_id)
 
-    url = next_topic&.relative_url
+    end
 
-    render json: {
-      next_topic_url: url
-    }
-  end
+    def approve
+
+      topic = Topic.find_by(id: params[:topic_id])
+
+      tags = topic.tags.pluck(:name)
+
+      tags -= [
+        SiteSetting.code_review_followup_tag,
+        SiteSetting.code_review_pending_tag
+      ]
+
+      tags << SiteSetting.code_review_approved_tag
+
+      DiscourseTagging.tag_topic_by_names(topic, Guardian.new(current_user), tags)
 
+      topic.add_moderator_post(
+        current_user,
+        nil,
+        bump: false,
+        post_type: Post.types[:small_action],
+        action_code: "approved"
+      )
+
+      render_next_topic(topic.category_id)
+
+    end
+
+    protected
+
+    def render_next_topic(category_id)
+      next_topic = Topic
+        .joins(:tags)
+        .where('tags.name = ?', SiteSetting.code_review_pending_tag)
+        .where(category_id: category_id)
+        .where('user_id <> ?', current_user.id)
+        .order('bumped_at asc')
+        .first
+
+      url = next_topic&.relative_url
+
+      render json: {
+        next_topic_url: url
+      }
+    end
+
+  end
 end
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index f63de84..237a8c1 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -1,9 +1,8 @@
 en:
   site_settings:
-    code_review_github_repo: 'name of github repos you wish to track eg: discourse/discourse'
-    code_review_category_name: 'category for github repo'
     code_review_enabled: 'enable Discourse code review'
     code_review_api_username: 'OAuth key of this username will be used for API calls, this means we get 5000 an hour vs 60'
     code_review_pending_tag: 'Tag to apply to pending commits'
     code_review_followup_tag: 'Tag to apply to follow up commits'
     code_review_approved_tag: 'Tag to apply to approved commits'
+    code_review_github_webhook_secret: 'web hook secret string to use use for https://sitename/code-review/webhook'
diff --git a/config/settings.yml b/config/settings.yml
index b56bc19..274d7d9 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -1,8 +1,7 @@
 plugins:
   code_review_enabled: false
-  code_review_github_repo: ""
-  code_review_category_name: ""
   code_review_api_username: ""
   code_review_pending_tag: "pending"
   code_review_approved_tag: "approved"
   code_review_followup_tag: "follow-up"
+  code_review_github_webhook_secret: ""
diff --git a/jobs/import_commits.rb b/jobs/import_commits.rb
deleted file mode 100644
index e0e2a4c..0000000
--- a/jobs/import_commits.rb
+++ /dev/null
@@ -1,172 +0,0 @@
-module Jobs
-
-  class ::DiscourseCodeReview::ImportCommits < Jobs::Scheduled
-    every 1.minute
-
-    def execute(args = nil)
-
-      return unless SiteSetting.code_review_enabled && SiteSetting.code_review_github_repo.present?
-
-      if SiteSetting.code_review_category_name.blank?
-        Rails.logger.warn("You must set the code review category name site setting")
-        return
-      end
-
-      category = Category.find_by(name: SiteSetting.code_review_category_name)
-      if !category
-        Rails.logger.warn("Can not find the category '#{SiteSetting.code_review_category_name}' so commits will not be updated")
-        return
-      end
-
-      import_commits(category_id: category.id)
-      import_comments
-    end
-
-    def import_commits(category_id:)
-      DiscourseCodeReview.commits_since.each do |commit|
-
-        link = <<~LINK
-          [<small>GitHub</small>](https://github.com/#{SiteSe

GitHub

1 Like