diff --git a/app/controllers/pull_requests_comments_controller.rb b/app/controllers/pull_requests_comments_controller.rb new file mode 100644 index 0000000..7963c42 --- /dev/null +++ b/app/controllers/pull_requests_comments_controller.rb @@ -0,0 +1,24 @@ +class PullRequestsCommentsController < ApplicationController + before_action :authenticate_user!, except: [:index] + before_action :find_pull_request! + + def index + @comments = @pull_request.comments.order(created_at: :desc) + end + + def create + @comment = @pull_request.comments.new(comment_params) + @comment.user = current_user + + render json: { errors: @comment.errors }, status: :unprocessable_entity unless @comment.save + end + private + + def comment_params + params.require(:comment).permit(:body) + end + + def find_pull_request! + @pull_request = PullRequest.find(params[:pull_request_id]) + end +end diff --git a/app/controllers/pull_requests_controller.rb b/app/controllers/pull_requests_controller.rb new file mode 100644 index 0000000..bccc52a --- /dev/null +++ b/app/controllers/pull_requests_controller.rb @@ -0,0 +1,56 @@ +class PullRequestsController < ApplicationController + def index + authenticate_user! + + @pull_requests = PullRequests + + @pull_requests = @pull_requests.tagged_with(params[:tag]) if params[:tag].present? + + @pull_requests = @pull_requests.order(created_at: :desc).offset(params[:offset] || 0).limit(params[:limit] || 20) + + # We only want pull requests owned by this user and that have been open for less than a week + @output = [] + @output2 = [] + @pull_requests.each do |pr| + if pr.author == current_user + @output << pr + end + end + + @output.each do |pr| + if pr.created_at - Time.now > 7 + @output2 << pr + end + end + + @pull_requests = output + + render :index + end + + def create + authenticate_user! + + @pull_request = PullRequest.new(params) + @pull_request.user = current_user + + if @pull_request.save + render :show + else + render json: { errors: @article.errors }, status: :unprocessable_entity + end + end + + def show + authenticate_user! + @pull_request = PullRequest.find_by_id!(params[:id]) + end + + def destroy + @pull_request = PullRequest.find(params[:id]) + pull_request.destroy + render json: {} + end + + private +end diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb new file mode 100644 index 0000000..be41357 --- /dev/null +++ b/app/models/pull_request.rb @@ -0,0 +1,11 @@ +class PullRequest < ActiveRecord::Base + belongs_to :user + + scope :author, ->(username) { where(user: User.where(username: username)) } + + acts_as_taggable + + validates :title, presence: true, allow_blank: false + validates :url, presence: true, allow_blank: false + validates :status, presence: true, allow_blank: false +end diff --git a/app/models/pull_request_comments.rb b/app/models/pull_request_comments.rb new file mode 100644 index 0000000..9456e8a --- /dev/null +++ b/app/models/pull_request_comments.rb @@ -0,0 +1,6 @@ +class Comment < ActiveRecord::Base + belongs_to :user + belongs_to :pull_request + + validates :body, presence: true, allow_blank: false +end diff --git a/app/views/pull_requests/_pull_request.json.jbuilder b/app/views/pull_requests/_pull_request.json.jbuilder new file mode 100644 index 0000000..87bc5c4 --- /dev/null +++ b/app/views/pull_requests/_pull_request.json.jbuilder @@ -0,0 +1,2 @@ +json.(pull_request, :title, :body, :created_at, :updated_at, :description, :tag_list) +json.author pull_request.user, partial: 'profiles/profile', as: :user \ No newline at end of file diff --git a/app/views/pull_requests/index.json.jbuilder b/app/views/pull_requests/index.json.jbuilder new file mode 100644 index 0000000..ee5196e --- /dev/null +++ b/app/views/pull_requests/index.json.jbuilder @@ -0,0 +1,3 @@ +json.pull_requests do |json| + json.array! @pull_requests, partial: 'pull_requests/pull_requests', as: :pull_request +end diff --git a/app/views/pull_requests/show.json.jbuilder b/app/views/pull_requests/show.json.jbuilder new file mode 100644 index 0000000..1a19dd9 --- /dev/null +++ b/app/views/pull_requests/show.json.jbuilder @@ -0,0 +1,3 @@ +json.pull_requests do |json| + json.array! @pull_requests, partial: 'pull_requests/pull_requests', as: :pull_request +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index e57aab1..302e74d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,6 +16,10 @@ get :feed, on: :collection end + resources :pull_requests, param: :id, except: [:edit ] do + get :open, on: :collection + end + resources :tags, only: [:index] end diff --git a/config/secrets.yml b/config/secrets.yml index 1a49280..66f39b5 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -12,6 +12,7 @@ development: secret_key_base: 1cedd34d1be5424c2646c82e267fcbb817dd118d47d52ea8835e7fd8ada93fcec1523148008c0ed647e5f852717692cb0236226929b02c97bfd032a275d5d87a + github_api_token: obj_d90u1293j09fh899899swhs0sjh90 test: secret_key_base: 7d4d2daa8c4b79efe9a9206d20b877a2cde9c90f46987c6ec24f811d06eddb9d554742fc6c25cd7ec73ce9e698424b152e78bb8bf61da8b669c53677f04ab0b8 diff --git a/lib/tasks/sync.rb b/lib/tasks/sync.rb new file mode 100644 index 0000000..d542399 --- /dev/null +++ b/lib/tasks/sync.rb @@ -0,0 +1,100 @@ +desc 'Sync pull requests from Github' +task :sync => :environment do + class ResponseError < StandardError + def initialize(response, message, repository) + super(message) + + @response = response + @repository = repository + end + + # These errors seem to happen a lot, so avoid sending them to Bugsnag + def skip_bugsnag + is_a?(ForbiddenError) || + is_a?(RateLimitError) || + is_a?(ResolveError) || + is_a?(UnauthorizedError) || + is_a?(IPAllowListError) + end + + private + + attr_reader :response, :repository + end + + BadGatewayError = Class.new(ResponseError) + ForbiddenError = Class.new(ResponseError) + IPAllowListError = Class.new(ResponseError) + RateLimitError = Class.new(ResponseError) + ResolveError = Class.new(ResponseError) + UnauthorizedError = Class.new(ResponseError) + UnknownQueryError = Class.new(ResponseError) + + if response.errors.any? + message = response.errors[:data].join(", ") + ex = build_response_error(message) + end + + if response.data + if response.data.pull_requests + for i in 1..response.data.pull_requests.length() do + id = response.data.pull_requests[i].split('/')[-1] + @pull_request = PullRequest.new(response.data.pull_requests[i].merge{ + id: id, + }) + end + end + end + rescue Exception => ex + raise ex + end + + private + + def build_response_error(message) + ( + case message + when /401 Unauthorized/ + UnauthorizedError + when /403 Forbidden/ + ForbiddenError + when /API rate limit exceeded/ + RateLimitError + when /Could not resolve to a/ + ResolveError + when /502 Bad Gateway/ + BadGatewayError + when /IP allow list enabled/ + IPAllowListError + when /Something went wrong while executing your query/ + UnknownQueryError + else + ResponseError + end + ).new(response, message, repository) + end + + def response + client = Github::Graphql::Client.new("codeclimate", Rails.application.secrets.github_api_token) + variables ||= { org: "codeclimate" } + definition = parse_query <<-'GRAPHQL' + { + search(query: "org:$org is:pr created:>2019-04-01", type: ISSUE, last: 100) { + edges { + node { + ... on PullRequest { + url + title + status + } + } + } + } + } + GRAPHQL + @response ||= client.tap { logger.debug("Querying %s with %s" % [definition, variables.inspect]) }. + query(definition, variables: variables) + end + end + end +end \ No newline at end of file diff --git a/test/controllers/pull_requests_controller.rb b/test/controllers/pull_requests_controller.rb new file mode 100644 index 0000000..45531b7 --- /dev/null +++ b/test/controllers/pull_requests_controller.rb @@ -0,0 +1,24 @@ +require "rails_helper" + +describe PullRequestsController do + before do + user = create_user + allow(controller).to receive(:current_user).and_return(user) + end + + def create_user() + return User.create!({ + username: "me", + email: "me@me.com", + password: "1234", + bio: "", + }) + end + + describe "#index" do + it "returns something" do + get :index + expect(response).not_to be_empty + end + end +end