diff --git a/README.md b/README.md index fae9bdf96..afc548a3d 100644 --- a/README.md +++ b/README.md @@ -2542,6 +2542,335 @@ http://localhost:3000/api//api/repositories/3868/delete_file | jq ``` --- +### 获取pull request文件列表 +``` +GET /api/:owner/:repo/pulls/:id/files.json +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/Jason/repo/1/files.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | +|id |是|int |pull request's id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|files_count |int|文件更改的总数量| +|total_addition |int|添加代码总行数| +|total_deletion |int|删除代码总行数| +|files |array|| +|-- name |string|当前文件名| +|-- old_name |string| 修改之前的文件名称,与name相同的话,说明文件名未更改| +|-- addition |int|文件添加的行数| +|-- deletion |int|文件删除的行数| +|-- type |int|文件类型, 1: 表示该文件只添加了内容,2: 表示该文件内容有修改, 3: 表示文件被删除或者改文件只删除了内容| +|-- isCreated |boolean|当前文件是否为新增文件, true: 是, false: 否| +|-- isDeleted |boolean|当前文件是否被删除, true: 是,false: 否| +|-- isBin |boolean|当前文件是否为二进制文件,true: 是,false: 否| +|-- isLFSFile |boolean|当前文件是否为LFS文件,true: 是,false: 否| +|-- isRenamed |boolean|当前文件是否被重命名,true: 是,false: 否| +|-- sections |array|| +|---- fileName |string|文件名称| +|---- lines |array|| +|------ leftIdx |string|文件变动之前所在行数| +|------ rightIdx |string|文件更改后所在行数| +|------ type |string|文件变更类型,1: 新增,2: 修改, 3: 删除, 4: diff统计信息| +|------ content |string|文件变更的内容| +|------ sectionInfo |object|| +|-------- path |string|文件相对仓库的路径| +|-------- lastLeftIdx |int|| +|-------- lastRightIdx |int|| +|-------- leftHunkSize |int|文件变更之前的行数| +|-------- rightHunkSize |int|文件变更之后的行数(及当前页面编辑器显示的总行数)| +|-------- leftIdx |int|文件变更之前所在行数| +|-------- rightIdx |int|文件变更之后所在行数(即:页面编辑器开始显示的行数)| + + +返回值 +```json +{ + "files_count": 6, + "total_addition": 447, + "total_deletion": 0, + "files": [ + { + "name": "文件.txt", + "old_name": "文件.txt", + "index": 6, + "addition": 2, + "deletion": 0, + "type": 1, + "isCreated": true, + "isDeleted": false, + "isBin": false, + "isLFSFile": false, + "isRenamed": false, + "isSubmodule": false, + "sections": [ + { + "fileName": "文件.txt", + "name": "", + "lines": [ + { + "leftIdx": 0, + "rightIdx": 0, + "type": 4, + "content": "@@ -0,0 +1,2 @@", + "sectionInfo": { + "path": null, + "lastLeftIdx": null, + "lastRightIdx": null, + "leftIdx": 0, + "rightIdx": 0, + "leftHunkSize": null, + "rightHunkSize": null + } + }, + { + "leftIdx": 0, + "rightIdx": 1, + "type": 2, + "content": "+用例图一致性更新", + "sectionInfo": null + }, + { + "leftIdx": 0, + "rightIdx": 2, + "type": 2, + "content": "+工程文件直接上传会有文件缺失,现在压缩后上传", + "sectionInfo": null + } + ] + } + ] + } + ] +} +``` +--- + +### 获取pull request的commits列表 +``` +GET /api/:owner/:repo/pulls/:id/commits.json +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/Jason/repo/1/commits.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | +|id |是|int |pull request's id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|commits_count |int|commits总数量| +|commits |array|| +|-- author |object|项目作者| +|---- login |string|用户login| +|---- name |string|用户姓名| +|---- image_url |string|用户头像| +|-- committer |object|commit提交用户| +|---- login |string|用户login| +|---- name |string|用户姓名| +|---- image_url |string|用户头像| +|-- timestamp |int|commit的unix时间戳| +|-- time_from_now|string|commit’s 提交时间距当前时间的时间值| +|-- message |string|commit说明信息| +|-- sha |string|commit’s sha值| + +返回值 +```json +{ + "commits_count": 1, + "commits": [ + { + "author": { + "id": 36480, + "login": "jasder", + "name": "段甲生", + "image_url": "avatars/User/b" + }, + "committer": { + "id": 36480, + "login": "jasder", + "name": "段甲生", + "image_url": "avatars/User/b" + }, + "timestamp": 1604382982, + "time_from_now": "3小时前", + "message": "add some file\n* Add the tag list page to the release page\n* Apply suggestions from code review\n* Add the tags list view\n* Add the delete tag way on ui\n* Not delete tag and clear message when delete a release\n", + "sha": "8f5faee0d3b3be1b8063e84da0c79dd75327b968" + } + ] +} +``` +--- + +### compare two commits +``` +GET /api/:owner/:repo/compare/{base}...{head}.json +``` +*示例* +``` +curl -X GET \ +http://localhost:3003/api/v1/repos/Jason/test-txt/compare/master...develop | jq + +curl -X GET \ +http://localhost:3003/api/v1/repos/jasder/test-txt/compare/master...Jason/test-txt:develop +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | +|base |是|string |pull request's id | +|head |是|string |pull request's id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|commits_count |int|commits总数量| +|commits |array|| +|-- author |object|项目作者| +|---- login |string|用户login| +|---- name |string|用户姓名| +|---- image_url |string|用户头像| +|-- committer |object|commit提交用户| +|---- login |string|用户login| +|---- name |string|用户姓名| +|---- image_url |string|用户头像| +|-- timestamp |int|commit的unix时间戳| +|-- time_from_now|string|commit’s 提交时间距当前时间的时间值| +|-- message |string|commit说明信息| +|-- sha |string|commit’s sha值| +|diff |array|| +|-- files_count |int|文件更改的总数量| +|-- total_addition |int|添加代码总行数| +|-- total_deletion |int|删除代码总行数| +|-- name |string|当前文件名| +|-- old_name |string| 修改之前的文件名称,与name相同的话,说明文件名未更改| +|-- addition |int|文件添加的行数| +|-- deletion |int|文件删除的行数| +|-- type |int|文件类型, 1: 表示该文件只添加了内容,2: 表示该文件内容有修改, 3: 表示文件被删除或者改文件只删除了内容| +|-- isCreated |boolean|当前文件是否为新增文件, true: 是, false: 否| +|-- isDeleted |boolean|当前文件是否被删除, true: 是,false: 否| +|-- isBin |boolean|当前文件是否为二进制文件,true: 是,false: 否| +|-- isLFSFile |boolean|当前文件是否为LFS文件,true: 是,false: 否| +|-- isRenamed |boolean|当前文件是否被重命名,true: 是,false: 否| +|-- sections |array|| +|---- fileName |string|文件名称| +|---- lines |array|| +|------ leftIdx |string|文件变动之前所在行数| +|------ rightIdx |string|文件更改后所在行数| +|------ type |string|文件变更类型,1: 新增,2: 修改, 3: 删除, 4: diff统计信息| +|------ content |string|文件变更的内容| +|------ sectionInfo |object|| +|-------- path |string|文件相对仓库的路径| +|-------- lastLeftIdx |int|| +|-------- lastRightIdx |int|| +|-------- leftHunkSize |int|文件变更之前的行数| +|-------- rightHunkSize |int|文件变更之后的行数(及当前页面编辑器显示的总行数)| +|-------- leftIdx |int|文件变更之前所在行数| +|-------- rightIdx |int|文件变更之后所在行数(即:页面编辑器开始显示的行数)| + +返回值 +```json +{ + "commits_count": 1, + "commits": [ + { + "author": { + "id": 36480, + "login": "jasder", + "name": "段甲生", + "image_url": "avatars/User/b" + }, + "committer": { + "id": 36480, + "login": "jasder", + "name": "段甲生", + "image_url": "avatars/User/b" + }, + "timestamp": 1604382982, + "time_from_now": "4小时前", + "message": "add some file\n* Add the tag list page to the release page\n* Apply suggestions from code review\n* Add the tags list view\n* Add the delete tag way on ui\n* Not delete tag and clear message when delete a release\n", + "sha": "8f5faee0d3b3be1b8063e84da0c79dd75327b968" + } + ], + "diff": { + "files_count": 6, + "total_addition": 447, + "total_deletion": 0, + "files": [ + { + "name": "build.go", + "old_name": "build.go", + "index": 1, + "addition": 33, + "deletion": 0, + "type": 1, + "isCreated": true, + "isDeleted": false, + "isBin": false, + "isLFSFile": false, + "isRenamed": false, + "isSubmodule": false, + "sections": [ + { + "fileName": "build.go", + "name": "", + "lines": [ + { + "leftIdx": 0, + "rightIdx": 0, + "type": 4, + "content": "@@ -0,0 +1,33 @@", + "sectionInfo": { + "path": "build.go", + "lastLeftIdx": 0, + "lastRightIdx": 0, + "leftIdx": 0, + "rightIdx": 1, + "leftHunkSize": 0, + "rightHunkSize": 33 + } + }, + { + "leftIdx": 0, + "rightIdx": 1, + "type": 2, + "content": "+// Copyright 2020 The Gitea Authors. All rights reserved.", + "sectionInfo": null + } + ] + } + ] + } + ] + } +} +``` +--- ### DevOps相关api diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index a4c17e90d..9d6efdcb6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -759,7 +759,7 @@ class ApplicationController < ActionController::Base end def load_repository - @repository ||= load_project.repository + @repository ||= load_project&.repository end private diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb new file mode 100644 index 000000000..a67dbd92b --- /dev/null +++ b/app/controllers/compare_controller.rb @@ -0,0 +1,15 @@ +class CompareController < ApplicationController + # skip_before_action :require_login + before_action :load_repository + + def index + end + + def show + base_ref = Addressable::URI.unescape(params[:base]) + @ref = head_ref = Addressable::URI.unescape(params[:head]) + @compare_result = Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base_ref, head_ref) + + # render json: @compare_result + end +end diff --git a/app/controllers/pull_requests_controller.rb b/app/controllers/pull_requests_controller.rb index a5a4d81bb..d233fdfce 100644 --- a/app/controllers/pull_requests_controller.rb +++ b/app/controllers/pull_requests_controller.rb @@ -1,9 +1,8 @@ class PullRequestsController < ApplicationController - before_action :require_login, except: [:index, :show] + before_action :require_login, except: [:index, :show, :files, :commits] before_action :load_repository - before_action :set_user, only: [:new, :get_branches] - before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos] - # before_action :get_relatived, only: [:edit] + before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits] + before_action :load_pull_request, only: [:files, :commits] include TagChosenHelper include ApplicationHelper @@ -24,11 +23,11 @@ class PullRequestsController < ApplicationController end def new - @all_branches = PullRequests::BranchesService.new(@user, @project).call + @all_branches = PullRequests::BranchesService.new(@owner, @project).call @is_fork = @project.forked_from_project_id.present? @projects_names = [{ - project_user_login: @user.try(:login), - project_name: "#{@user.try(:show_real_name)}/#{@repository.try(:identifier)}", + project_user_login: @owner.try(:login), + project_name: "#{@owner.try(:show_real_name)}/#{@repository.try(:identifier)}", project_id: @project.identifier, id: @project.id }] @@ -45,7 +44,7 @@ class PullRequestsController < ApplicationController end def get_branches - branch_result = PullRequests::BranchesService.new(@user, @project).call + branch_result = PullRequests::BranchesService.new(@owner, @project).call render json: branch_result # return json: branch_result end @@ -235,16 +234,19 @@ class PullRequestsController < ApplicationController end - private - def set_user - @user = @project.owner + def files + @files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gpid) + # render json: @files_result end - def set_repository - @repository = @project.repository - @user = @project.owner - normal_status(-1, "仓库不存在") unless @repository.present? - normal_status(-1, "用户不存在") unless @user.present? + def commits + @commits_result = Gitea::PullRequest::CommitsService.call(@owner.login, @project.identifier, @pull_request.gpid) + # render json: @commits_result + end + + private + def load_pull_request + @pull_request = PullRequest.find params[:id] end def find_pull_request diff --git a/app/helpers/compare_helper.rb b/app/helpers/compare_helper.rb new file mode 100644 index 000000000..d920da301 --- /dev/null +++ b/app/helpers/compare_helper.rb @@ -0,0 +1,2 @@ +module CompareHelper +end diff --git a/app/services/gitea/pull_request/commits_service.rb b/app/services/gitea/pull_request/commits_service.rb new file mode 100644 index 000000000..aca2067cc --- /dev/null +++ b/app/services/gitea/pull_request/commits_service.rb @@ -0,0 +1,40 @@ +# List commits on a pull request +class Gitea::PullRequest::CommitsService < Gitea::ClientService + attr_reader :owner, :repo, :pull_number, :token + + # GET /repos/{owner}/{repo}/pulls/{pull_number}/commits + # owner: 用户 + # repo: 仓库名称/标识 + # pull_number: pull request主键id + # eg: + # Gitea::PullRequest::FilesService.call('jasder', 'repo_identifier', 1) + def initialize(owner, repo, pull_number, token=nil) + @owner = owner + @repo = repo + @token = token + @pull_number = pull_number + end + + def call + response = get(url, params) + render_result(response) + end + + private + def params + Hash.new.merge(token: owner) + end + + def url + "/repos/#{owner}/#{repo}/pulls/#{pull_number}/commits".freeze + end + + def render_result(response) + case response.status + when 200 + JSON.parse(response.body) + else + nil + end + end +end diff --git a/app/services/gitea/pull_request/files_service.rb b/app/services/gitea/pull_request/files_service.rb new file mode 100644 index 000000000..9785588e2 --- /dev/null +++ b/app/services/gitea/pull_request/files_service.rb @@ -0,0 +1,40 @@ +# List pull requests files +class Gitea::PullRequest::FilesService < Gitea::ClientService + attr_reader :owner, :repo, :pull_number, :token + + # GET /repos/{owner}/{repo}/pulls/{pull_number}/files + # owner: 用户 + # repo: 仓库名称/标识 + # pull_number: pull request主键id + # eg: + # Gitea::PullRequest::FilesService.call('jasder', 'repo_identifier', 1) + def initialize(owner, repo, pull_number, token=nil) + @owner = owner + @repo = repo + @token = token + @pull_number = pull_number + end + + def call + response = get(url, params) + render_result(response) + end + + private + def params + Hash.new.merge(token: token) + end + + def url + "/repos/#{owner}/#{repo}/pulls/#{pull_number}/files".freeze + end + + def render_result(response) + case response.status + when 200 + JSON.parse(response.body) + else + nil + end + end +end diff --git a/app/services/gitea/repository/commits/compare_service.rb b/app/services/gitea/repository/commits/compare_service.rb new file mode 100644 index 000000000..ea0c648ce --- /dev/null +++ b/app/services/gitea/repository/commits/compare_service.rb @@ -0,0 +1,38 @@ +# Compare two commits +class Gitea::Repository::Commits::CompareService < Gitea::ClientService + attr_reader :owner, :repo, :base, :head, :token + + # sha: the commit hash + # ex: + # Gitea::Repository::Commits::CompareService.call('owner', 'repo_identifier', 'master', 'jasder/repo_identifier:develop') + def initialize(owner, repo, base, head, token=nil) + @token = token + @owner = owner + @base = base + @repo = repo + @head = head + end + + def call + response = get(url, params) + render_result(response) + end + + private + def params + Hash.new.merge(token: token) + end + + def url + "/repos/#{owner}/#{repo}/compare/#{base}...#{head}".freeze + end + + def render_result(response) + case response.status + when 200 + JSON.parse(response.body) + else + {status: -1, message: "#{body['message']}"} + end + end +end diff --git a/app/views/compare/index.json.jbuilder b/app/views/compare/index.json.jbuilder new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/compare/show.json.jbuilder b/app/views/compare/show.json.jbuilder new file mode 100644 index 000000000..2db2a6da0 --- /dev/null +++ b/app/views/compare/show.json.jbuilder @@ -0,0 +1,9 @@ +json.commits_count @compare_result['Commits']&.size +json.commits @compare_result['Commits'], partial: 'pull_requests/commit', as: :commit + +json.diff do + json.files_count @compare_result['Diff']['NumFiles'] + json.total_addition @compare_result['Diff']['TotalAddition'] + json.total_deletion @compare_result['Diff']['TotalDeletion'] + json.files @compare_result['Diff']['Files'], partial: 'pull_requests/diff_file', as: :file +end diff --git a/app/views/pull_requests/_commit.json.jbuilder b/app/views/pull_requests/_commit.json.jbuilder new file mode 100644 index 000000000..023c2f302 --- /dev/null +++ b/app/views/pull_requests/_commit.json.jbuilder @@ -0,0 +1,13 @@ +json.author do + author = User.find_by(login: commit['Author']['Name']) + json.partial! 'repositories/commit_author', locals: { user: author } +end + +json.committer do + author = User.find_by(login: commit['Committer']['Name']) + json.partial! 'repositories/commit_author', locals: { user: author } +end +json.timestamp render_unix_time(commit['Committer']['When']) +json.time_from_now time_from_now(commit['Committer']['When']) +json.message commit['CommitMessage'] +json.sha commit['Sha'] diff --git a/app/views/pull_requests/_diff_file.json.jbuilder b/app/views/pull_requests/_diff_file.json.jbuilder new file mode 100644 index 000000000..6efea4382 --- /dev/null +++ b/app/views/pull_requests/_diff_file.json.jbuilder @@ -0,0 +1,40 @@ +json.name file['Name'] +json.old_name file['OldName'] +json.index file['Index'] +json.addition file['Addition'] +json.deletion file['Deletion'] +json.type file['Type'] +json.isCreated file['IsCreated'] +json.isDeleted file['IsDeleted'] +json.isBin file['IsBin'] +json.isLFSFile file['IsLFSFile'] +json.isRenamed file['IsRenamed'] +json.isSubmodule file['IsSubmodule'] +json.isLFSFile file['IsLFSFile'] +json.sections do + json.array! file['Sections'] do |section| + json.fileName section['FileName'] + json.name section['Name'] + json.lines do + json.array! section['Lines'] do |line| + json.leftIdx line['LeftIdx'] + json.rightIdx line['RightIdx'] + json.type line['Type'] + json.content line['Content'] + json.sectionInfo do + if line['SectionInfo'].blank? + json.nil! + else + json.path line['SectionInfo']['Path'] + json.lastLeftIdx line['SectionInfo']['LastLeftIdx'] + json.lastRightIdx line['SectionInfo']['LastRightIdx'] + json.leftIdx line['SectionInfo']['LeftIdx'] + json.rightIdx line['SectionInfo']['RightIdx'] + json.leftHunkSize line['SectionInfo']['LeftHunkSize'] + json.rightHunkSize line['SectionInfo']['RightHunkSize'] + end + end + end + end + end +end diff --git a/app/views/pull_requests/commits.json.jbuilder b/app/views/pull_requests/commits.json.jbuilder new file mode 100644 index 000000000..57ffa726e --- /dev/null +++ b/app/views/pull_requests/commits.json.jbuilder @@ -0,0 +1,2 @@ +json.commits_count @commits_result.size +json.commits @commits_result, partial: 'commit', as: :commit diff --git a/app/views/pull_requests/files.json.jbuilder b/app/views/pull_requests/files.json.jbuilder new file mode 100644 index 000000000..744f70c6c --- /dev/null +++ b/app/views/pull_requests/files.json.jbuilder @@ -0,0 +1,4 @@ +json.files_count @files_result['NumFiles'] +json.total_addition @files_result['TotalAddition'] +json.total_deletion @files_result['TotalDeletion'] +json.files @files_result['Files'], partial: 'diff_file', as: :file diff --git a/config/routes.rb b/config/routes.rb index caa931c31..163eb2d2e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,5 @@ Rails.application.routes.draw do - + require 'sidekiq/web' require 'admin_constraint' @@ -337,11 +337,18 @@ Rails.application.routes.draw do end end + # compare + resources :compare, only: [:index, :create] + get '/compare/:base...:head' => 'compare#show', :as => 'compare', + :constraints => { base: /.+/, head: /.+/ } + resources :pull_requests, :path => :pulls, except: [:destroy] do member do post :pr_merge # post :check_merge post :refuse_merge + get :files + get :commits end collection do post :check_can_merge