diff --git a/Gemfile b/Gemfile index cd6c4b91..281dd705 100644 --- a/Gemfile +++ b/Gemfile @@ -100,6 +100,7 @@ gem 'rails-i18n', '~> 5.1' # job gem 'sidekiq' gem 'sinatra' +gem "sidekiq-cron", "~> 1.1" # batch insert gem 'bulk_insert' diff --git a/Gemfile.lock b/Gemfile.lock index a6beea40..cbd598f5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -118,12 +118,17 @@ GEM enumerize (2.3.1) activesupport (>= 3.2) erubi (1.9.0) + et-orbi (1.2.4) + tzinfo execjs (2.7.0) faraday (0.15.4) multipart-post (>= 1.2, < 3) ffi (1.12.2) font-awesome-sass (4.7.0) sass (>= 3.2) + fugit (1.4.1) + et-orbi (~> 1.1, >= 1.1.8) + raabro (~> 1.4) globalid (0.4.2) activesupport (>= 4.2.0) grape-entity (0.7.1) @@ -211,6 +216,7 @@ GEM prettier (0.18.2) public_suffix (4.0.3) puma (3.12.2) + raabro (1.4.0) rack (2.0.9) rack-cors (1.1.1) rack (>= 2.0.0) @@ -353,6 +359,9 @@ GEM rack (< 2.1.0) rack-protection (>= 1.5.0) redis (>= 3.3.5, < 5) + sidekiq-cron (1.2.0) + fugit (~> 1.1) + sidekiq (>= 4.2.1) simple_form (5.0.2) actionpack (>= 5.0) activemodel (>= 5.0) @@ -477,6 +486,7 @@ DEPENDENCIES searchkick selenium-webdriver sidekiq + sidekiq-cron (~> 1.1) simple_form simple_xlsx_reader sinatra diff --git a/app/controllers/ci/base_controller.rb b/app/controllers/ci/base_controller.rb index 20a9cb15..c17105cd 100644 --- a/app/controllers/ci/base_controller.rb +++ b/app/controllers/ci/base_controller.rb @@ -11,6 +11,11 @@ class Ci::BaseController < ApplicationController @ci_user, @repo = Ci::Repo.find_with_namespace(namespace, id) end + def load_all_repo + namespace = current_user.login + @repos = Ci::Repo.find_all_with_namespace(namespace) + end + private def authorize_access_project! unless @project.manager?(current_user) @@ -45,14 +50,22 @@ class Ci::BaseController < ApplicationController end def connect_to_ci_db(options={}) - if !(current_user && !current_user.is_a?(AnonymousUser) && !current_user.devops_uninit?) + current = current_user + owner = params[:owner] + if owner + current = User.find_by(login: owner) + end + + if !(current && !current.is_a?(AnonymousUser) && !current.devops_uninit?) return end - if current_user.ci_cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_TRUSTIE + + if current.ci_cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_TRUSTIE connect_to_trustie_ci_database(options) else connect_to_ci_database(options) end + end end diff --git a/app/controllers/ci/builds_controller.rb b/app/controllers/ci/builds_controller.rb index 4900a890..e6caf893 100644 --- a/app/controllers/ci/builds_controller.rb +++ b/app/controllers/ci/builds_controller.rb @@ -8,7 +8,6 @@ class Ci::BuildsController < Ci::BaseController def index @user = current_user - scope = @repo.builds scope = Ci::Builds::ListQuery.call(@repo, params) diff --git a/app/controllers/ci/cloud_accounts_controller.rb b/app/controllers/ci/cloud_accounts_controller.rb index 2d2c83a1..043d24fe 100644 --- a/app/controllers/ci/cloud_accounts_controller.rb +++ b/app/controllers/ci/cloud_accounts_controller.rb @@ -5,6 +5,7 @@ class Ci::CloudAccountsController < Ci::BaseController before_action :load_project, only: %i[create activate] before_action :authorize_owner!, only: %i[create activate] before_action :load_repo, only: %i[activate] + before_action :load_all_repo, only: %i[unbind] before_action :find_cloud_account, only: %i[show oauth_grant] before_action :validate_params!, only: %i[create bind] before_action only: %i[create bind] do @@ -95,6 +96,13 @@ class Ci::CloudAccountsController < Ci::BaseController def unbind ActiveRecord::Base.transaction do + if current_user.ci_cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_TRUSTIE + if @repos + @repos.each do |repo| + repo.deactivate! + end + end + end unbind_account! render_ok end diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb index e5e61598..63ca58aa 100644 --- a/app/controllers/compare_controller.rb +++ b/app/controllers/compare_controller.rb @@ -6,10 +6,26 @@ class CompareController < ApplicationController end def show - base_ref = Addressable::URI.unescape(params[:base]) - @ref = head_ref = Addressable::URI.unescape(params[:head]&.split('.json')[0]) - @compare_result = Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base_ref, head_ref) + compare + end - # render json: @compare_result + private + def compare + base, head = compare_params + + # TODO: 处理fork的项目向源项目发送PR的base、head参数问题 + @compare_result ||= + head.include?(":") ? gitea_compare(base, head) : gitea_compare(head, base) + end + + def compare_params + base = Addressable::URI.unescape(params[:base]) + head = params[:head].include?('json') ? params[:head]&.split('.json')[0] : params[:head] + + [base, head] + end + + def gitea_compare(base, head) + Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head) end end diff --git a/app/controllers/concerns/ci/cloud_account_manageable.rb b/app/controllers/concerns/ci/cloud_account_manageable.rb index ce60de3b..00c42305 100644 --- a/app/controllers/concerns/ci/cloud_account_manageable.rb +++ b/app/controllers/concerns/ci/cloud_account_manageable.rb @@ -16,6 +16,9 @@ module Ci::CloudAccountManageable # 2. 生成oauth2应用程序的client_id和client_secrete gitea_oauth = Gitea::Oauth2::CreateService.call(current_user.gitea_token, {name: "pipeline-#{SecureRandom.hex(8)}", redirect_uris: ["#{cloud_account.drone_url}/login"]}) logger.info "######### gitea_oauth: #{gitea_oauth}" + + raise 'Gitea接口异常' if gitea_oauth['client_id'].blank? + oauth = Oauth.new(client_id: gitea_oauth['client_id'], client_secret: gitea_oauth['client_secret'], redirect_uri: gitea_oauth['redirect_uris'], @@ -54,12 +57,16 @@ module Ci::CloudAccountManageable result && !result.blank? ? cloud_account : nil end - # trustie提供服务器,绑定流程 - def trustie_bind_account! - + def trustie_drone_server_config # 读取drone配置信息 config = Rails.application.config_for(:configuration).symbolize_keys! trustie_drone_config = config[:trustie_drone].symbolize_keys! + return trustie_drone_config + end + + # trustie提供服务器,绑定流程 + def trustie_bind_account! + trustie_drone_config = trustie_drone_server_config raise 'trustie_drone config missing' if trustie_drone_config.blank? # 创建云账号 @@ -71,6 +78,9 @@ module Ci::CloudAccountManageable #生成oauth2应用程序的client_id和client_secrete gitea_oauth = Gitea::Oauth2::CreateService.call(current_user.gitea_token, {name: "pipeline-#{SecureRandom.hex(8)}", redirect_uris: ["#{cloud_account.drone_url}/login"]}) logger.info "######### gitea_oauth: #{gitea_oauth}" + + raise 'Gitea接口异常' if gitea_oauth['client_id'].blank? + oauth = Oauth.new(client_id: gitea_oauth['client_id'], client_secret: gitea_oauth['client_secret'], redirect_uri: gitea_oauth['redirect_uris'], @@ -91,7 +101,11 @@ module Ci::CloudAccountManageable if cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_SELF @connection.execute("DROP DATABASE IF EXISTS #{current_user.login}_drone") # TOTO drop drone database + else + #删除drone用户 + @trustie_db_connection.execute("DELETE FROM users WHERE user_login = '#{cloud_account.account}'") end + cloud_account.destroy! unless cloud_account.blank? current_user.unbind_account! end @@ -114,7 +128,12 @@ module Ci::CloudAccountManageable return [true, "你已经绑定了云帐号."] unless current_user.ci_cloud_account.blank? ip_num = IPAddr.new(devops_params[:ip_num]).to_i - Ci::CloudAccount.exists?(ip_num: ip_num) ? [true, "#{devops_params[:ip_num]}服务器已被使用."] : [false, nil] + + #自有服务器进行判断 + cloud_account = current_user.ci_cloud_account + if cloud_account && cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_SELF + Ci::CloudAccount.exists?(ip_num: ip_num) ? [true, "#{devops_params[:ip_num]}服务器已被使用."] : [false, nil] + end end def check_trustie_bind_cloud_account! @@ -126,8 +145,16 @@ module Ci::CloudAccountManageable unix_time = Time.now.to_i # 目前直接操作db,可以建立对应的model进行操作 - sql = "INSERT INTO oauth2_grant ( user_id, application_id, counter, created_unix, updated_unix ) VALUES ( #{current_user.gitea_uid}, #{gitea_oauth_id}, 0, #{unix_time}, #{unix_time} );" + sql = "REPLACE INTO oauth2_grant ( user_id, application_id, counter, created_unix, updated_unix ) VALUES ( #{current_user.gitea_uid}, #{gitea_oauth_id}, 0, #{unix_time}, #{unix_time} );" connection.execute(sql) + + #如果使用trustie提供的服务器,需要多增加一条授权信息 + if current_user.ci_cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_TRUSTIE + trustie_drone_config = trustie_drone_server_config + admin_application_id = trustie_drone_config[:admin_application_id] + sql = "REPLACE INTO oauth2_grant ( user_id, application_id, counter, created_unix, updated_unix ) VALUES ( #{current_user.gitea_uid}, #{admin_application_id}, 0, #{unix_time}, #{unix_time} );" + connection.execute(sql) + end end def gitea_oauth_grant!(password, oauth) @@ -137,7 +164,8 @@ module Ci::CloudAccountManageable # redirect_uri eg: # https://localhost:3000/login/oauth/authorize?client_id=94976481-ad0e-4ed4-9247-7eef106007a2&redirect_uri=http%3A%2F%2F121.69.81.11%3A80%2Flogin&response_type=code&state=9cab990b9cfb1805 redirect_uri = CGI.escape("#{@cloud_account.drone_url}/login") - grant_url = "#{Gitea.gitea_config[:domain]}/login/oauth/authorize?client_id=#{oauth&.client_id}&redirect_uri=#{redirect_uri}&response_type=code&state=#{state}" + clientId = client_id(oauth) + grant_url = "#{Gitea.gitea_config[:domain]}/login/oauth/authorize?client_id=#{clientId}&redirect_uri=#{redirect_uri}&response_type=code&state=#{state}" logger.info "[gitea] grant_url: #{grant_url}" conn = Faraday.new(url: grant_url) do |req| @@ -171,4 +199,14 @@ module Ci::CloudAccountManageable params.permit(:account, :secret, :ip_num) end + def client_id(oauth) + #如果是使用trustie服务器使用管理员用户的clientId + if current_user.ci_cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_TRUSTIE + trustie_drone_config = trustie_drone_server_config + return trustie_drone_config[:client_id] + else + return oauth&.client_id + end + end + end diff --git a/app/controllers/pull_requests_controller.rb b/app/controllers/pull_requests_controller.rb index 54873ec3..979191b8 100644 --- a/app/controllers/pull_requests_controller.rb +++ b/app/controllers/pull_requests_controller.rb @@ -87,8 +87,10 @@ class PullRequestsController < ApplicationController if @issue.update_attributes(@issue_params) if @pull_request.update_attributes(@local_params.compact) - gitea_request = Gitea::PullRequest::UpdateService.new(@project.owner, @repository.try(:identifier), @requests_params, @pull_request.try(:gpid)).call - if gitea_request + gitea_pull = Gitea::PullRequest::UpdateService.call(@owner.login, @repository.identifier, + @pull_request.gpid, @requests_params, current_user.gitea_token) + + if gitea_pull[:status] === :success if params[:issue_tag_ids].present? params[:issue_tag_ids].each do |tag| IssueTagsRelate.create(issue_id: @issue.id, issue_tag_id: tag) @@ -119,9 +121,8 @@ class PullRequestsController < ApplicationController def refuse_merge ActiveRecord::Base.transaction do begin - @pull_request.update(status: 2) - @pull_request.issue.update(status_id: 5) - normal_status(1, "已拒绝") + colsed = PullRequests::CloseService.call(@owner, @repository, @pull_request, current_user) + colsed === true ? normal_status(1, "已拒绝") : normal_status(-1, '合并失败') rescue => e normal_status(-1, e.message) raise ActiveRecord::Rollback @@ -147,15 +148,10 @@ class PullRequestsController < ApplicationController else ActiveRecord::Base.transaction do begin - requests_params = { - Do: params[:do], - MergeMessageField: params[:body], - MergeTitleField: params[:title] - } - merge_pr = Gitea::PullRequest::MergeService.call(current_user.gitea_token, @project.owner.login, - @repository.try(:identifier), @pull_request.try(:gpid), requests_params) - if @pull_request.update_attribute(:status, 1) && merge_pr[:status].to_i == 200 - @pull_request&.project_trends&.update_all(action_type: "close") + result = PullRequests::MergeService.call(@owner, @repository, @pull_request, current_user, params) + + if result && @pull_request.merge! + @pull_request.project_trend_status! @issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id) normal_status(1, "合并成功") else diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 80143eaa..5ad6363a 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -4,10 +4,20 @@ class UsersController < ApplicationController before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users] before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users] before_action :require_login, only: %i[me list] - before_action :connect_to_ci_database, only: :get_user_info, if: -> { current_user && !current_user.is_a?(AnonymousUser) && current_user.devops_certification? } - + before_action :connect_to_ci_db, only: [:get_user_info] skip_before_action :check_sign, only: [:attachment_show] + def connect_to_ci_db(options={}) + if !(current_user && !current_user.is_a?(AnonymousUser) && current_user.devops_certification?) + return + end + if current_user.ci_cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_TRUSTIE + connect_to_trustie_ci_database(options) + else + connect_to_ci_database(options) + end + end + def list scope = User.active.recent.like(params[:search]).includes(:user_extension) @total_count = scope.size diff --git a/app/helpers/ci/builds_helper.rb b/app/helpers/ci/builds_helper.rb index c0e59106..0e352ced 100644 --- a/app/helpers/ci/builds_helper.rb +++ b/app/helpers/ci/builds_helper.rb @@ -8,4 +8,8 @@ module Ci::BuildsHelper return nil if end_time == 0 || start_time == 0 game_spend_time(end_time - start_time) end + + def render_build_author login + User.find_by(login: login) + end end diff --git a/app/jobs/sync_repo_update_time_job.rb b/app/jobs/sync_repo_update_time_job.rb new file mode 100644 index 00000000..c2337ab9 --- /dev/null +++ b/app/jobs/sync_repo_update_time_job.rb @@ -0,0 +1,25 @@ +class SyncRepoUpdateTimeJob < ApplicationJob + queue_as :default + + def perform(*args) + # Do something later + Project.forge.find_each do |project| + update_repo_time!(project) + end + end + + private + def gitea_repo_updated_at(project) + admin = User.where(admin: true).select(:id, :gitea_token, :gitea_uid).last + + return nil if project.gpid.blank? + + result = Gitea::Repository::GetByIdService.call(project.gpid, admin.gitea_token) + + result[:status] === :success ? result[:body]['updated_at'] : nil + end + + def update_repo_time!(project) + project.set_updated_on gitea_repo_updated_at(project) + end +end diff --git a/app/libs/ci/drone/api.rb b/app/libs/ci/drone/api.rb index dd346d7b..c2bb0c0f 100644 --- a/app/libs/ci/drone/api.rb +++ b/app/libs/ci/drone/api.rb @@ -78,5 +78,11 @@ class Ci::Drone::API < Ci::Drone::Request def sync_repos post(endpoint, "/api/users/repos", drone_token: drone_token) end - + + # Creates a user. + # POST /api/users + def create_user + post(endpoint, "/api/users", {login: options[:login], email: options[:email], avatar_url:options[:avatar_url],active:true, drone_token: options[:token]}) + end + end diff --git a/app/models/ci/repo.rb b/app/models/ci/repo.rb index 8396cfa9..6fb42e04 100644 --- a/app/models/ci/repo.rb +++ b/app/models/ci/repo.rb @@ -14,6 +14,12 @@ class Ci::Repo < Ci::RemoteBase [user, repo] end + def self.find_all_with_namespace(namespace_path) + logger.info "########namespace_path: #{namespace_path}" + repos = Ci::Repo.where(repo_namespace: namespace_path) + return repos + end + def activate!(ci_user_id) update(repo_active: 1, repo_signer: generate_code, diff --git a/app/models/issue_status.rb b/app/models/issue_status.rb index a7ec34f8..a58346ea 100644 --- a/app/models/issue_status.rb +++ b/app/models/issue_status.rb @@ -17,6 +17,13 @@ # class IssueStatus < ApplicationRecord + ADD = 1 + SOLVING = 2 + SOLVED = 3 + FEEDBACK = 4 + CLOSED = 5 + REJECTED = 6 + has_many :issues belongs_to :project, optional: true end diff --git a/app/models/project.rb b/app/models/project.rb index 9378227e..6a5e9545 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -284,4 +284,9 @@ class Project < ApplicationRecord ps.increment!(:mirror_projects_count) unless ps.blank? end + def set_updated_on(time) + return if time.blank? + update_column(:updated_on, time) + end + end diff --git a/app/models/project_trend.rb b/app/models/project_trend.rb index 5858768b..8c55c4f9 100644 --- a/app/models/project_trend.rb +++ b/app/models/project_trend.rb @@ -18,6 +18,9 @@ # class ProjectTrend < ApplicationRecord + CLOSE = 'close' + CREATE = 'create' + belongs_to :project belongs_to :trend, polymorphic: true, optional: true belongs_to :user diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb index 06f702f7..17a86144 100644 --- a/app/models/pull_request.rb +++ b/app/models/pull_request.rb @@ -24,8 +24,12 @@ # class PullRequest < ApplicationRecord - #status 0 默认未合并, 1表示合并, 2表示请求拒绝 include DunCheckAble + #status 0 默认未合并, 1表示合并, 2表示请求拒绝(或已关闭) + OPEN = 0 + MERGED = 1 + CLOSED = 2 + belongs_to :issue belongs_to :user belongs_to :project, :counter_cache => true @@ -43,6 +47,14 @@ class PullRequest < ApplicationRecord update_column(:gpid, gitea_pull_number) end + def merge! + update_column(:status, PullRequest::MERGED) + end + + def project_trend_status! + self&.project_trends&.update_all(action_type: ProjectTrend::CLOSE) + end + # TODO: sync educoder platform repo's for update some statistics count def self.update_some_count PullRequest.includes(:user, :project).select(:id, :user_id, :gpid, :project_id, :fork_project_id).each do |pr| diff --git a/app/services/gitea/pull_request/close_service.rb b/app/services/gitea/pull_request/close_service.rb new file mode 100644 index 00000000..aed5251b --- /dev/null +++ b/app/services/gitea/pull_request/close_service.rb @@ -0,0 +1,22 @@ +class Gitea::PullRequest::CloseService < Gitea::PullRequest::UpdateService + attr_reader :owner, :repo, :base, :number, :token + + # params: + # owner: owner of the repo + # repo: name of the repo + # base: branch name of base + # number: number of pull request + # token: token of gitea user + # eq: + # Gitea::PullRequest::CloseService.call(owner.login, repo.identifier, pull.gpid, pull.base, current_user.gitea_token) + def initialize(owner, repo, number, base,token=nil) + colse_pull_params = Hash.new.merge(base: base, state: 'closed').compact + + super(owner, repo, number, colse_pull_params, token) + end + + def call + super + end + +end diff --git a/app/services/gitea/pull_request/merge_service.rb b/app/services/gitea/pull_request/merge_service.rb index 2129bbea..c33c8781 100644 --- a/app/services/gitea/pull_request/merge_service.rb +++ b/app/services/gitea/pull_request/merge_service.rb @@ -18,7 +18,9 @@ class Gitea::PullRequest::MergeService < Gitea::ClientService end def call - post(url, request_params) + response = post(url, request_params) + + render_200_no_body(response) end private @@ -27,7 +29,6 @@ class Gitea::PullRequest::MergeService < Gitea::ClientService end def request_params - Hash.new.merge(token: token, data: params) + Hash.new.merge(token: token, data: params.compact) end - end diff --git a/app/services/gitea/pull_request/open_service.rb b/app/services/gitea/pull_request/open_service.rb new file mode 100644 index 00000000..affdfe11 --- /dev/null +++ b/app/services/gitea/pull_request/open_service.rb @@ -0,0 +1,22 @@ +class Gitea::PullRequest::OpenService < Gitea::PullRequest::UpdateService + attr_reader :owner, :repo, :base, :number, :token + + # params: + # owner: owner of the repo + # repo: name of the repo + # base: branch name of base + # number: number of pull request + # token: token of gitea user + # eq: + # Gitea::PullRequest::OpenService.new(owner.login, repo.identifier, pr.gpid, pr.base, current_user.gitea_token) + def initialize(owner, repo, number, base, token=nil) + open_pull_params = Hash.new.merge(base: base, state: 'open').compact + + super(owner, repo, number, open_pull_params, token) + end + + def call + super + end + +end diff --git a/app/services/gitea/pull_request/update_service.rb b/app/services/gitea/pull_request/update_service.rb index a83afe40..a68981f2 100644 --- a/app/services/gitea/pull_request/update_service.rb +++ b/app/services/gitea/pull_request/update_service.rb @@ -1,26 +1,54 @@ class Gitea::PullRequest::UpdateService < Gitea::ClientService - attr_reader :user, :repo, :params,:pull_request_id + attr_reader :owner, :repo, :params, :number, :token - - def initialize(user, repo, params,pull_request_id) - @user = user + # params: + # { + # "assignee": "string", + # "assignees": [ + # "string" + # ], + # "base": "string", + # "body": "string", + # "due_date": "2021-01-11T10:11:52.074Z", + # "labels": [ + # 0 + # ], + # "milestone": 0, + # "state": "string", + # "title": "string", + # "unset_due_date": true + # } + def initialize(owner, repo, number, params, token=nil) + @owner = owner @repo = repo @params = params - @pull_request_id = pull_request_id + @number = number + @token = token end def call - put(url, request_params) + response = patch(url, request_params) + + status, message, body = render_response(response) + json_format(status, message, body) end private def request_params - Hash.new.merge(token: @user.gitea_token, data: @params) + Hash.new.merge(token: token, data: @params) end def url - "/repos/#{@user.try(:login)}/#{@repo}/pulls/#{@pull_request_id}".freeze + "/repos/#{owner}/#{repo}/pulls/#{number}".freeze + end + + def json_format(status, message, body) + case status + when 201 then success(body) + else + error(message, status) + end end end diff --git a/app/services/gitea/repository/get_by_id_service.rb b/app/services/gitea/repository/get_by_id_service.rb index c633c6b7..74f45708 100644 --- a/app/services/gitea/repository/get_by_id_service.rb +++ b/app/services/gitea/repository/get_by_id_service.rb @@ -1,31 +1,32 @@ class Gitea::Repository::GetByIdService < Gitea::ClientService - attr_reader :owner, :repo_id + attr_reader :token, :id - def initialize(owner, repo_id) - @owner = owner - @repo_id = repo_id + def initialize(id, token=nil) + @token = token + @id = id end def call response = get(url, params) - render_result(response) + + status, message, body = render_response(response) + json_format(status, message, body) end private def params - Hash.new.merge(token: owner.gitea_token) + Hash.new.merge(token: token) end def url - "/repositories/#{repo_id}".freeze + "/repositories/#{id}".freeze end - def render_result(response) - case response.status - when 200 - JSON.parse(response.body) + def json_format(status, message, body) + case status + when 200 then success(body) else - nil + error(message, status) end end end diff --git a/app/services/pull_requests/close_service.rb b/app/services/pull_requests/close_service.rb new file mode 100644 index 00000000..e0ac19b4 --- /dev/null +++ b/app/services/pull_requests/close_service.rb @@ -0,0 +1,33 @@ +class PullRequests::CloseService < ApplicationService + attr_reader :owner, :repo, :pull, :current_user + + # eq: + # PullRequests::CloseService.call(owner, repo, pull, current_user) + def initialize(owner, repo, pull, current_user) + @owner = owner + @repo = repo + @pull = pull + @current_user = current_user + end + + def call + ActiveRecord::Base.transaction do + return false if close_gitea_pull[:status] != :success + + update_pull_status! + return true + end + end + + private + + def close_gitea_pull + Gitea::PullRequest::CloseService.call(@owner.login, @repo.identifier, + @pull.gpid, @pull.base, current_user.gitea_token) + end + + def update_pull_status! + @pull.update(status: PullRequest::CLOSED) + @pull.issue.update(status_id: IssueStatus::CLOSED) + end +end diff --git a/app/services/pull_requests/merge_service.rb b/app/services/pull_requests/merge_service.rb new file mode 100644 index 00000000..a20ee3aa --- /dev/null +++ b/app/services/pull_requests/merge_service.rb @@ -0,0 +1,36 @@ +class PullRequests::MergeService < ApplicationService + attr_reader :owner, :repo, :pull, :current_user, :params + + # eq: + # PullRequests::MergeService.call(owner, repo, pull, current_user, params) + def initialize(owner, repo, pull, current_user, params) + @owner = owner + @repo = repo + @pull = pull + @current_user = current_user + @params = params + end + + def call + ActiveRecord::Base.transaction do + gitea_pull_merge! + end + end + + private + + def gitea_pull_merge! + result = Gitea::PullRequest::MergeService.call(@current_user.gitea_token, @owner.login, + @repo.identifier, @pull.gpid, gitea_merge_pull_params) + + result[:status] === 200 ? true : false + end + + def gitea_merge_pull_params + { + Do: params[:do], + MergeMessageField: params[:body], + MergeTitleField: params[:title] + } + end +end diff --git a/app/services/pull_requests/open_service.rb b/app/services/pull_requests/open_service.rb new file mode 100644 index 00000000..3081e52b --- /dev/null +++ b/app/services/pull_requests/open_service.rb @@ -0,0 +1,33 @@ +class PullRequests::OpenService < ApplicationService + attr_reader :owner, :repo, :pull, :current_user + + # eq: + # PullRequests::OpenService.call(owner, repo, pull, current_user) + def initialize(owner, repo, pull, current_user) + @owner = owner + @repo = repo + @pull = pull + @current_user = current_user + end + + def call + ActiveRecord::Base.transaction do + return false if open_gitea_pull[:status] != :success + + update_pull_status! + return true + end + end + + private + + def open_gitea_pull + Gitea::PullRequest::OpenService.call(@owner.login, @repo.identifier, + @pull.gpid, @pull.base, @current_user.gitea_token) + end + + def update_pull_status! + @pull.update(status: PullRequest::OPEN) + @pull.issue.update(status_id: IssueStatus::SOLVING) + end +end diff --git a/app/views/ci/builds/_build.json.jbuilder b/app/views/ci/builds/_build.json.jbuilder index 1c1afcbf..669be1f1 100644 --- a/app/views/ci/builds/_build.json.jbuilder +++ b/app/views/ci/builds/_build.json.jbuilder @@ -7,7 +7,7 @@ json.action build.build_action json.error build.build_error if build.build_status == 'error' json.message build.build_message json.author do - json.partial! 'author', user: current_user + json.partial! 'author', user: render_build_author(build.build_author) end json.started format_utc_time build.build_started json.finished format_utc_time build.build_finished diff --git a/app/views/compare/show.json.jbuilder b/app/views/compare/show.json.jbuilder index 8f95bbcb..8257cc7f 100644 --- a/app/views/compare/show.json.jbuilder +++ b/app/views/compare/show.json.jbuilder @@ -1,5 +1,29 @@ json.commits_count @compare_result['Commits']&.size -json.commits @compare_result['Commits'], partial: 'pull_requests/commit', as: :commit +# json.commits @compare_result['Commits'], partial: 'pull_requests/commit', as: :commit +json.commits do + json.array! @compare_result['Commits'] do |commit| + json.author do + # TODO: 获取头像地址待优化 + forge_user = User.includes(:user_extension).select(:id, :login).find_by(login: commit['Author']['Name']) + json.login commit['Author']['Name'] + json.name commit['Author']['Name'] + json.image_url forge_user.nil? ? '' : url_to_avatar(forge_user) + end + + json.committer do + # TODO: 获取头像地址待优化 + forge_user = User.includes(:user_extension).select(:id, :login).find_by(login: commit['Committer']['Name']) + json.login commit['Committer']['Name'] + json.name commit['Committer']['Name'] + json.image_url forge_user.nil? ? '' : url_to_avatar(forge_user) + end + json.timestamp render_unix_time(commit['Committer']['When']) + json.time_from_now time_from_now(commit['Committer']['When']) + json.created_at render_format_time_with_date(commit['Committer']['When']) + json.message commit['CommitMessage'] + json.sha commit['Sha'] + end +end json.diff do if @compare_result['Diff'].blank? @@ -8,6 +32,54 @@ 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, locals: {sha: @compare_result['LatestSha']} + + # TODO: 解决render partil耗时间问题 + # json.files @compare_result['Diff']['Files'], partial: 'pull_requests/diff_file', as: :file, locals: {sha: @compare_result['LatestSha']} + json.files do + json.array! @compare_result['Diff']['Files'] do |file| + json.sha @compare_result['LatestSha'] + 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 + end + end + end end diff --git a/app/views/pull_requests/files.json.jbuilder b/app/views/pull_requests/files.json.jbuilder index b40fe606..9708ba84 100644 --- a/app/views/pull_requests/files.json.jbuilder +++ b/app/views/pull_requests/files.json.jbuilder @@ -1,4 +1,52 @@ 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, locals: {sha: @files_result['LatestSha']} + +# TODO: 解决 render partil file性能问题 +# json.files @files_result['Files'], partial: 'diff_file', as: :file, locals: {sha: @files_result['LatestSha']} +json.files do + json.array! @files_result['Files'] do |file| + json.sha @files_result['LatestSha'] + 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 + end + +end diff --git a/app/views/pull_requests/show.json.jbuilder b/app/views/pull_requests/show.json.jbuilder index 61bbc915..14dfefef 100644 --- a/app/views/pull_requests/show.json.jbuilder +++ b/app/views/pull_requests/show.json.jbuilder @@ -1,5 +1,6 @@ json.partial! "commons/success" json.project_name @project.name +json.identifier @project.identifier json.pr_time time_from_now(@pull_request.updated_at) json.commits_count @pull_request.commits_count json.files_count @pull_request.files_count diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index b3f2d057..79a0e296 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -3,6 +3,11 @@ sidekiq_url = redis_config["url"] Sidekiq.configure_server do |config| config.redis = { url: sidekiq_url } + + schedule_file = "config/schedule.yml" + if File.exists?(schedule_file) + Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file) + end end Sidekiq.configure_client do |config| diff --git a/config/routes.rb b/config/routes.rb index f520002b..be1b67f7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ Rails.application.routes.draw do require 'sidekiq/web' + require 'sidekiq/cron/web' require 'admin_constraint' # mount Sidekiq::Web => '/sidekiq', :constraints => AdminConstraint.new diff --git a/config/schedule.yml b/config/schedule.yml new file mode 100644 index 00000000..2b4269ac --- /dev/null +++ b/config/schedule.yml @@ -0,0 +1,5 @@ +sync_gitea_repo_updated_at: + # second minute hour day month date + cron: "0 0 24 * *" + class: "SyncRepoUpdateTimeJob" + queue: default