From 89c97e93f603a3f2643b38dbff63a2f024bc19ac Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Wed, 7 Feb 2024 16:10:41 +0000 Subject: [PATCH] Add commits endpoint to repository routes --- app/controllers/api/v1/commits_controller.rb | 22 +++++ app/models/commit.rb | 3 + .../api/v1/commits/_commit.json.jbuilder | 1 + app/views/api/v1/commits/index.json.jbuilder | 1 + .../v1/repositories/_repository.json.jbuilder | 1 + config/routes.rb | 1 + openapi/api/v1/openapi.yaml | 84 ++++++++++++++++++- .../api/v1/commits_controller_test.rb | 19 +++++ 8 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 app/controllers/api/v1/commits_controller.rb create mode 100644 app/views/api/v1/commits/_commit.json.jbuilder create mode 100644 app/views/api/v1/commits/index.json.jbuilder create mode 100644 test/controllers/api/v1/commits_controller_test.rb diff --git a/app/controllers/api/v1/commits_controller.rb b/app/controllers/api/v1/commits_controller.rb new file mode 100644 index 0000000..851c348 --- /dev/null +++ b/app/controllers/api/v1/commits_controller.rb @@ -0,0 +1,22 @@ +class Api::V1::CommitsController < Api::V1::ApplicationController + def index + @host = Host.find_by_name!(params[:host_id]) + @repository = @host.repositories.find_by!('lower(full_name) = ?', params[:repository_id].downcase) + + scope = @repository.commits.order('timestamp DESC') + + scope = scope.since(params[:since]) if params[:since].present? + scope = scope.until(params[:until]) if params[:until].present? + + if params[:sort].present? || params[:order].present? + sort = params[:sort] || 'timestamp' + order = params[:order] || 'desc' + sort_options = sort.split(',').zip(order.split(',')).to_h + scope = scope.order(sort_options) + else + scope = scope.order('timestamp DESC') + end + + @pagy, @commits = pagy_countless(@repository.commits.order('timestamp DESC')) + end +end \ No newline at end of file diff --git a/app/models/commit.rb b/app/models/commit.rb index ef7e98f..0be26a8 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -3,4 +3,7 @@ class Commit < ApplicationRecord has_one :host, through: :repository validates :sha, presence: true, uniqueness: { scope: :repository_id } + + scope :since, ->(date) { where('timestamp > ?', date) } + scope :until, ->(date) { where('timestamp < ?', date) } end diff --git a/app/views/api/v1/commits/_commit.json.jbuilder b/app/views/api/v1/commits/_commit.json.jbuilder new file mode 100644 index 0000000..eb5eab1 --- /dev/null +++ b/app/views/api/v1/commits/_commit.json.jbuilder @@ -0,0 +1 @@ +json.extract! commit, :sha, :message, :author, :committer, :timestamp, :merge \ No newline at end of file diff --git a/app/views/api/v1/commits/index.json.jbuilder b/app/views/api/v1/commits/index.json.jbuilder new file mode 100644 index 0000000..1bf0b2c --- /dev/null +++ b/app/views/api/v1/commits/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @commits, partial: 'api/v1/commits/commit', as: :commit \ No newline at end of file diff --git a/app/views/api/v1/repositories/_repository.json.jbuilder b/app/views/api/v1/repositories/_repository.json.jbuilder index 047e78c..d042bdd 100644 --- a/app/views/api/v1/repositories/_repository.json.jbuilder +++ b/app/views/api/v1/repositories/_repository.json.jbuilder @@ -1 +1,2 @@ json.extract! repository, :full_name, :default_branch, :committers, :total_commits, :total_committers, :total_bot_commits, :total_bot_committers, :mean_commits, :dds, :past_year_committers, :past_year_total_commits, :past_year_total_committers, :past_year_total_bot_commits, :past_year_total_bot_committers, :past_year_mean_commits, :past_year_dds, :last_synced_at, :last_synced_commit, :created_at, :updated_at +json.commits_url api_v1_host_repository_commits_url(repository.host, repository) \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 71b6384..a8441e8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -22,6 +22,7 @@ member do get 'ping', to: 'repositories#ping' end + resources :commits, only: [:index] end end end diff --git a/openapi/api/v1/openapi.yaml b/openapi/api/v1/openapi.yaml index 05e04d8..63115bc 100644 --- a/openapi/api/v1/openapi.yaml +++ b/openapi/api/v1/openapi.yaml @@ -172,6 +172,70 @@ paths: application/json: schema: $ref: '#/components/schemas/Repository' + /hosts/{hostName}/repositories/{repoName}/commits: + get: + summary: get a list of commits from a repository + operationId: getRepositoryCommits + parameters: + - in: path + name: hostName + schema: + type: string + required: true + description: name of host + - in: path + name: repoName + schema: + type: string + required: true + description: name of repository + - name: page + in: query + description: pagination page number + required: false + schema: + type: integer + - name: per_page + in: query + description: Number of records to return + required: false + schema: + type: integer + - name: since + in: query + description: filter by commits since given time + required: false + schema: + type: string + format: date-time + - name: until + in: query + description: filter by commits until given time + required: false + schema: + type: string + format: date-time + - name: sort + in: query + description: field to order results by + required: false + schema: + type: string + - name: order + in: query + description: direction to order results by + required: false + schema: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Commit' components: schemas: Host: @@ -239,4 +303,22 @@ components: format: date-time created_at: type: string - format: date-time \ No newline at end of file + format: date-time + commits_url: + type: string + Commit: + type: object + properties: + sha: + type: string + message: + type: string + author: + type: string + committer: + type: string + timestamp: + type: string + format: date-time + merge: + type: boolean \ No newline at end of file diff --git a/test/controllers/api/v1/commits_controller_test.rb b/test/controllers/api/v1/commits_controller_test.rb new file mode 100644 index 0000000..fef5c68 --- /dev/null +++ b/test/controllers/api/v1/commits_controller_test.rb @@ -0,0 +1,19 @@ +require 'test_helper' + +class ApiV1CommitsControllerTest < ActionDispatch::IntegrationTest + setup do + @host = Host.create(name: 'GitHub', url: 'https://github.com', kind: 'github') + @repository = @host.repositories.create(full_name: 'ecosyste-ms/repos', last_synced_at: Time.now, total_commits: 100, total_committers: 10) + @commit = @repository.commits.create(sha: '1234567890', timestamp: Time.now, author: 'author', message: 'message') + end + + test 'list commits for a repository' do + get api_v1_host_repository_commits_path(host_id: @host.name, repository_id: @repository.full_name) + assert_response :success + assert_template 'commits/index', file: 'commits/index.json.jbuilder' + + actual_response = JSON.parse(@response.body) + + assert_equal actual_response.length, 1 + end +end \ No newline at end of file