| @@ -0,0 +1,24 @@ | |||
| class Api::V1::Projects::SyncRepositoriesController < Api::V1::BaseController | |||
| before_action :require_public_and_member_above | |||
| def create | |||
| @sync_repositories = Api::V1::Projects::SyncRepositories::CreateService.call(@project, sync_repository_params) | |||
| end | |||
| def sync | |||
| @sync_repositories = SyncRepository.where(project: @project) | |||
| @sync_repository_branches = SyncRepositoryBranch.where(sync_repository_id: @sync_repositories) | |||
| @sync_repositories.each do |item| | |||
| TouchSyncJob.perform_later(item) | |||
| end | |||
| @sync_repository_branches.each do |item| | |||
| TouchSyncJob.perform_later(item) | |||
| end | |||
| end | |||
| private | |||
| def sync_repository_params | |||
| param.permit(:type, :external_token, :external_repo_address, :sync_granularity, :external_branch_name, :gitlink_branch_name, :first_sync_direction) | |||
| end | |||
| end | |||
| @@ -0,0 +1,24 @@ | |||
| class TouchSyncJob < ApplicationJob | |||
| queue_as :default | |||
| def perform(touchable) | |||
| puts "aaaa" | |||
| case touchable.class.to_s | |||
| when 'SyncRepositories::Github' || 'SyncRepositories::Gitee' | |||
| Reposync::SyncRepoService.call(touchable.repo_name) | |||
| when 'SyncRepositoryBranch' | |||
| sync_repository = touchable.sync_repository | |||
| result = [] | |||
| if sync_repository.sync_direction == 1 | |||
| result = Reposync::SyncBranchService.call(sync_repository.repo_name, touchable.gitlink_branch_name, sync_repository.sync_direction) | |||
| else | |||
| result = Reposync::SyncBranchService.call(sync_repository.repo_name, touchable.external_branch_name, sync_repository.sync_direction) | |||
| end | |||
| if result.is_a?(Array) | |||
| touchable.update_column(:sync_status, 1) | |||
| else | |||
| touchable.update_column(:sync_status, 2) | |||
| end | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,22 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: sync_repositories | |||
| # | |||
| # id :integer not null, primary key | |||
| # project_id :integer | |||
| # type :string(255) | |||
| # repo_name :string(255) | |||
| # external_repo_address :string(255) | |||
| # sync_granularity :integer | |||
| # sync_direction :integer | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_sync_repositories_on_project_id (project_id) | |||
| # | |||
| class SyncRepositories::Gitee < SyncRepository | |||
| end | |||
| @@ -0,0 +1,21 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: sync_repositories | |||
| # | |||
| # id :integer not null, primary key | |||
| # project_id :integer | |||
| # type :string(255) | |||
| # repo_name :string(255) | |||
| # external_repo_address :string(255) | |||
| # sync_granularity :integer | |||
| # sync_direction :integer | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_sync_repositories_on_project_id (project_id) | |||
| # | |||
| class SyncRepositories::Github < SyncRepository | |||
| end | |||
| @@ -0,0 +1,25 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: sync_repositories | |||
| # | |||
| # id :integer not null, primary key | |||
| # project_id :integer | |||
| # type :string(255) | |||
| # repo_name :string(255) | |||
| # external_repo_address :string(255) | |||
| # sync_granularity :integer | |||
| # sync_direction :integer | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_sync_repositories_on_project_id (project_id) | |||
| # | |||
| class SyncRepository < ApplicationRecord | |||
| belongs_to :project | |||
| validates :repo_name, uniqueness: { message: "已存在" } | |||
| end | |||
| @@ -0,0 +1,23 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: sync_repository_branches | |||
| # | |||
| # id :integer not null, primary key | |||
| # sync_repository_id :integer | |||
| # gitlink_branch_name :string(255) | |||
| # external_branch_name :string(255) | |||
| # sync_time :datetime | |||
| # sync_status :integer default("0") | |||
| # reposync_branch_id :integer | |||
| # created_at :datetime not null | |||
| # updated_at :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_sync_repository_branches_on_sync_repository_id (sync_repository_id) | |||
| # | |||
| class SyncRepositoryBranch < ApplicationRecord | |||
| belongs_to :sync_repository | |||
| end | |||
| @@ -0,0 +1,95 @@ | |||
| class Api::V1::Projects::SyncRepositories::CreateService < ApplicationService | |||
| include ActiveModel::Model | |||
| attr_reader :project, :type, :external_token, :external_repo_address, :sync_granularity, :external_branch_name, :gitlink_branch_name, :first_sync_direction | |||
| attr_accessor :sync_repository1, :sync_repository2 | |||
| validates :type, inclusion: {in: %w(SyncRepositories::Gitee SyncRepositories::Github)} | |||
| validates :external_repo_address, format: { with: CustomRegexp::URL_REGEX, multiline: true, message: "地址格式不正确" } | |||
| validates :sync_granularity, :first_sync_direction, inclusion: {in: [1,2]} | |||
| validate :check_gitlink_branch_name | |||
| def initialize(project, params) | |||
| @project = project | |||
| @type = params[:type] | |||
| @external_token = params[:external_token] | |||
| @external_repo_address = params[:external_repo_address] | |||
| @sync_granularity = params[:sync_granularity].to_i | |||
| @external_branch_name = params[:external_branch_name] | |||
| @gitlink_branch_name = params[:gitlink_branch_name] | |||
| @first_sync_direction = params[:first_sync_direction].to_i | |||
| end | |||
| def call | |||
| raise Error, errors.full_messages.join(",") unless valid? | |||
| if sync_granularity == 2 | |||
| # 创建两个不同方向的同步仓库 | |||
| create_sync_repository | |||
| # 创建两个不同方向的同步分支 | |||
| create_sync_repository_branch | |||
| # 第一次同步 | |||
| touch_first_sync_branch | |||
| else | |||
| create_sync_repository | |||
| touch_first_sync | |||
| end | |||
| create_webhook | |||
| end | |||
| def check_gitlink_branch_name | |||
| if sync_granularity == 2 | |||
| result = $gitea_hat_client.get_repos_branch_name_set_by_owner_repo(project&.owner&.login, project&.identifier) rescue nil | |||
| raise Error, '分支不存在' if !result.include?(gitlink_branch_name) | |||
| end | |||
| end | |||
| private | |||
| def create_sync_repository | |||
| repository1 = Reposync::CreateSyncRepoService.call(repo_name(1), gitlink_repo_address, external_repo_address, sync_granularity, 1) | |||
| repository2 = Reposync::CreateSyncRepoService.call(repo_name(2), gitlink_repo_address, external_repo_address, sync_granularity, 2) | |||
| @sync_repository1 = SyncRepository.create!(project: project, type: type, repo_name: repo_name(1), external_repo_address: external_repo_address, sync_granularity: sync_granularity, sync_direction: 1) | |||
| @sync_repository2 = SyncRepository.create!(project: project, type: type, repo_name: repo_name(2), external_repo_address: external_repo_address, sync_granularity: sync_granularity, sync_direction: 2) | |||
| end | |||
| def create_sync_repository_branch | |||
| branch1 = Reposync::CreateSyncBranchService.call(repo_name(1),gitlink_branch_name, external_branch_name) | |||
| branch2 = Reposync::CreateSyncBranchService.call(repo_name(2),gitlink_branch_name, external_branch_name) | |||
| @sync_repository_branch1 = SyncRepositoryBranch.create!(sync_repository: @sync_repository1, gitlink_branch_name: gitlink_branch_name, external_branch_name: external_branch_name ) | |||
| @sync_repository_branch2 = SyncRepositoryBranch.create!(sync_repository: @sync_repository2, gitlink_branch_name: gitlink_branch_name, external_branch_name: external_branch_name) | |||
| end | |||
| def touch_first_sync | |||
| first_sync_direction == 1 ? TouchSyncJob.perform_later(@sync_repository1) : TouchSyncJob.perform_later(@sync_repository2) | |||
| end | |||
| def touch_first_sync_branch | |||
| first_sync_direction == 1 ? TouchSyncJob.perform_later(@sync_repository_branch1) : TouchSyncJob.perform_later(@sync_repository_branch2) | |||
| end | |||
| def create_webhook | |||
| webhook_params = { | |||
| active: true, | |||
| branch_filter: '*', | |||
| http_method: 'POST', | |||
| url: "#{Rails.application.config_for(:configuration)['platform_url']}/api/v1/#{project&.owner&.login}/#{project&.identifier}/sync_repositories/sync", | |||
| content_type: 'json', | |||
| type: 'reposync', | |||
| events: ["push"] | |||
| } | |||
| Api::V1::Projects::Webhooks::CreateService.call(project, webhook_params) | |||
| end | |||
| def repo_name(sync_direction) | |||
| if type == "SyncRepositories::Gitee" | |||
| return "gitee:#{project.owner&.login}:#{project.identifier}:#{sync_granularity}:#{sync_direction}" | |||
| else | |||
| return "github:#{project.owner&.login}:#{project.identifier}:#{sync_granularity}:#{sync_direction}" | |||
| end | |||
| end | |||
| def gitlink_repo_address | |||
| "#{EduSetting.get("gitlink_repo_domain")}/#{project.owner&.login}/#{project.identifier}.git" | |||
| end | |||
| end | |||
| @@ -8,7 +8,7 @@ class Api::V1::Projects::Webhooks::CreateService < ApplicationService | |||
| validates :active, inclusion: {in: [true, false]} | |||
| validates :http_method, inclusion: { in: %w(POST GET), message: "请输入正确的请求方式"} | |||
| validates :content_type, inclusion: { in: %w(json form), message: "请输入正确的Content Type"} | |||
| validates :type, inclusion: {in: %w(gitea slack discord dingtalk telegram msteams feishu matrix jianmu softbot), message: "请输入正确的Webhook Type"} | |||
| validates :type, inclusion: {in: %w(gitea slack discord dingtalk telegram msteams feishu matrix jianmu softbot reposync), message: "请输入正确的Webhook Type"} | |||
| def initialize(project, params, token=nil) | |||
| @project = project | |||
| @owner = project&.owner.login | |||
| @@ -78,6 +78,11 @@ defaults format: :json do | |||
| # projects文件夹下的 | |||
| scope module: :projects do | |||
| resources :sync_repositories, only: [:create] do | |||
| collection do | |||
| post :sync | |||
| end | |||
| end | |||
| resource :dataset, only: [:create, :update, :show] | |||
| resources :actions, module: 'actions' do | |||
| collection do | |||
| @@ -0,0 +1,14 @@ | |||
| class CreateSyncRepositories < ActiveRecord::Migration[5.2] | |||
| def change | |||
| create_table :sync_repositories do |t| | |||
| t.references :project | |||
| t.string :type | |||
| t.string :repo_name | |||
| t.string :external_repo_address | |||
| t.integer :sync_granularity | |||
| t.integer :sync_direction, comment: "1表示从gitlink到外部2表示从外部到gitlink" | |||
| t.timestamps | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,14 @@ | |||
| class CreateSyncRepositoryBranches < ActiveRecord::Migration[5.2] | |||
| def change | |||
| create_table :sync_repository_branches do |t| | |||
| t.references :sync_repository | |||
| t.string :gitlink_branch_name, comment: 'gitlink分支' | |||
| t.string :external_branch_name, comment: '外部仓库分支' | |||
| t.datetime :sync_time | |||
| t.integer :sync_status, default: 0 | |||
| t.integer :reposync_branch_id | |||
| t.timestamps | |||
| end | |||
| end | |||
| end | |||