-
Notifications
You must be signed in to change notification settings - Fork 0
PRs #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
PRs #1
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| class Comment < ActiveRecord::Base | ||
| belongs_to :user | ||
| belongs_to :pull_request | ||
|
|
||
| validates :body, presence: true, allow_blank: false | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| json.pull_requests do |json| | ||
| json.array! @pull_requests, partial: 'pull_requests/pull_requests', as: :pull_request | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| json.pull_requests do |json| | ||
| json.array! @pull_requests, partial: 'pull_requests/pull_requests', as: :pull_request | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| desc 'Sync pull requests from Github' | ||
| task :sync => :environment do | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In six months I think you'll find yourself typing |
||
| class ResponseError < StandardError | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A part of me is surprised this isn't defined somewhere else in the codebase already - these error names are very generic and high level, so we want one of two things here:
If you're not sure which of the two to do, then let me know and we can have a conversation about it - you'll be able to make the decision afterwards. |
||
| 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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ..... why do these errors happen a lot? Errors are a way for the server to communicate with us, so if we're doing something wrong, we probably shouldn't ignore it. Here, it seems to indicate we're asking for too much too fast. We should look for a tool that helps us stay within the acceptable bounds as defined by Github's API terms of use. |
||
| def skip_bugsnag | ||
| is_a?(ForbiddenError) || | ||
| is_a?(RateLimitError) || | ||
| is_a?(ResolveError) || | ||
| is_a?(UnauthorizedError) || | ||
| is_a?(IPAllowListError) | ||
| end | ||
|
|
||
| private | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PLZ TO USE AUTOINDENT OMG |
||
|
|
||
| attr_reader :response, :repository | ||
| end | ||
|
|
||
| BadGatewayError = Class.new(ResponseError) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this! Simple, concise, and super-clear. |
||
| 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? | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not entirely certain there's any code that runs and generates a |
||
| message = response.errors[:data].join(", ") | ||
| ex = build_response_error(message) | ||
| end | ||
|
|
||
| if response.data | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm nested if and for loop? Maybe extract a method here? |
||
| 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{ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we're going to continually override the value of It looks like we might want to separate this into a few different operations to make it more readable; |
||
| 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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This name is too generic, and it hides the fact that this code is making the HTTP call. I would suggest something like |
||
| 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| require "rails_helper" | ||
|
|
||
| describe PullRequestsController do | ||
| before do | ||
| user = create_user | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we're using rspec, |
||
| allow(controller).to receive(:current_user).and_return(user) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note to self, do we want this here ? |
||
| end | ||
|
|
||
| def create_user() | ||
| return User.create!({ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't need to add this to the database - this slows down the test suite |
||
| 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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a great test to start with, but it doesn't test real product behavior, so it needs to evolve a little. |
||
| end | ||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These three definitions of
@pull_requestshere look like they are business logic (which PRs do we want and how?) and that is usually best handled by ascopein the model, rather than defined in the controller itself (bonus: much easier to test!).