From c181abce81481c950632afb000311022e61d32d4 Mon Sep 17 00:00:00 2001 From: Jasder <2053003901@@qq.com> Date: Wed, 15 Jul 2020 16:53:38 +0800 Subject: [PATCH] =?UTF-8?q?FIX=20=E5=AE=8C=E5=96=84devops=E6=B5=81?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/dev_ops/builds_controller.rb | 30 +++- app/libs/dev_ops/drone/api.rb | 41 +++-- app/libs/dev_ops/drone/ci.rb | 2 +- app/libs/dev_ops/drone/request.rb | 147 ++++++------------ app/models/dev_ops/cloud_account.rb | 1 + app/models/repository.rb | 1 + config/routes.rb | 10 +- ...repository_ref_to_dev_ops_cloud_account.rb | 7 + 8 files changed, 127 insertions(+), 112 deletions(-) create mode 100644 db/migrate/20200715075831_add_repository_ref_to_dev_ops_cloud_account.rb diff --git a/app/controllers/dev_ops/builds_controller.rb b/app/controllers/dev_ops/builds_controller.rb index 24d8b99d7..0cf160a10 100644 --- a/app/controllers/dev_ops/builds_controller.rb +++ b/app/controllers/dev_ops/builds_controller.rb @@ -3,9 +3,37 @@ class DevOps::BuildsController < ApplicationController before_action :find_project def index + cloud_account = @repo.dev_ops_cloud_account + result = DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier).builds + + render json: result end - def show + def detail + cloud_account = @repo.dev_ops_cloud_account + result = DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: params[:number]).build + + render json: result + end + + def restart + cloud_account = @repo.dev_ops_cloud_account + result = DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: params[:number]).restart + + render json: result + end + + def delete + cloud_account = @repo.dev_ops_cloud_account + result = DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: params[:number]).stop + render json: result + end + + def logs + cloud_account = @repo.dev_ops_cloud_account + result = DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, build: params[:build], stage: params[:stage], step: sync_params[:step]).logs + + render json: result end private diff --git a/app/libs/dev_ops/drone/api.rb b/app/libs/dev_ops/drone/api.rb index 08dafcb42..860e54557 100644 --- a/app/libs/dev_ops/drone/api.rb +++ b/app/libs/dev_ops/drone/api.rb @@ -1,12 +1,12 @@ class DevOps::Drone::API < DevOps::Drone::Request - attr_reader :drone_token, :drone_url, :owner, :repo, :options + attr_reader :drone_token, :endpoint, :owner, :repo, :options # drone_token: # owner: repo's owner name or login # repo: repo's identifier - def initialize(drone_token, drone_url, owner, repo, options={}) + def initialize(drone_token, endpoint, owner, repo, options={}) @drone_token = drone_token - @drone_url = drone_url + @endpoint = endpoint @owner = owner @repo = repo @options = options @@ -15,40 +15,59 @@ class DevOps::Drone::API < DevOps::Drone::Request # Build List # GET api/repos/{owner}/{name}/builds # eq: - # DevOps::Drone::API + # DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier) def builds - request(:get, drone_url, "api/repos/#{owner}/#{repo}/builds", drone_token: drone_token) + get(endpoint, "api/repos/#{owner}/#{repo}/builds", drone_token: drone_token) end # Build Info # GET api/repos/{owner}/{name}/builds/{number} + # eq: + # DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.endpoint, project.owner.login, project.identifier, number: number).build def build - request(:get, "api/repos/#{owner}/#{repo}/builds/#{number}", drone_token: drone_token) + get(endpoint, "api/repos/#{owner}/#{repo}/builds/#{options[:number]}", drone_token: drone_token) end # Update .trustie-pipeline.yml file - # PATCH api/repos/{owner}/{name} + # PATCH api/repos/{owner}/{name}\ + # eq: + # DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.endpoint, project.owner.login, project.identifier, config_path: config_path).config_yml def config_yml - request(:patch, "/api/repos/#{owner}/#{repo}", drone_token: drone_token, config_path: config_path) + patch(endpoint, "/api/repos/#{owner}/#{repo}", drone_token: drone_token, config_path: options[:config_path]) end # Activate user's project with Drone CI # POST api/repos/{owner}/{name} + # eq: + # DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.endpoint, project.owner.login, project.identifier).avtivate def activate - request(:post, "/api/repos/#{owner}/#{repo}", drone_token: drone_token) + post(endpoint, "/api/repos/#{owner}/#{repo}", drone_token: drone_token) end # Build Restart # POST api/repos/{owner}/{name}/builds/{number} # Restart the specified build. Please note this api requires read and write access to the repository and the request parameter {build} is not the build id but the build number. + # eq: + # DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: number).restart def restart - request(:post, "/api/repos/#{owner}/#{repo}/builds/#{number}", drone_token: drone_token) + post(endpoint, "/api/repos/#{owner}/#{repo}/builds/#{options[:number]}", drone_token: drone_token) end # Build Stop # DELETE api/repos/{owner}/{name}/builds/{number} # Stop the specified build. Please note this api requires administrative privileges and the request parameter {build} is not the build id but the build number. + # eq: + # DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: number).stop def stop - request(:delete, "/api/repos/#{owner}/#{repo}/builds/#{number}", drone_token: drone_token) + delete(endpoint, "/api/repos/#{owner}/#{repo}/builds/#{options[:number]}", drone_token: drone_token) + end + + # Build Logs + # GET /api/repos/{owner}/{repo}/builds/{build}/logs/{stage}/{step} + # Please note this api requires read access to the repository. + # eq: + # DevOps::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, build: build, stage: stage, step: step).logs + def logs + get(endpoint, "/api/repos/#{owner}/#{repo}/builds/#{options[:build]}/logs/#{options[:stage]}/#{options[:step]}", drone_token: drone_token) end end diff --git a/app/libs/dev_ops/drone/ci.rb b/app/libs/dev_ops/drone/ci.rb index 13eed9ba5..cfa67cdc2 100644 --- a/app/libs/dev_ops/drone/ci.rb +++ b/app/libs/dev_ops/drone/ci.rb @@ -5,7 +5,7 @@ class DevOps::Drone::Ci # username: drone server's account # password: drone server's password # eq: - # DevOps::Drone::Ci.new(@cloud_account.drone_ip, @cloud_account.account, @cloud_account.visible_secret).get_token + # DevOps::Drone::Ci.new(@cloud_account.drone_ip, @cloud_account.account, @cloud_account.visible_secret, current_user.login).get_token def initialize(host, username, password, gitea_username) @host = host @username = username diff --git a/app/libs/dev_ops/drone/request.rb b/app/libs/dev_ops/drone/request.rb index 7e059dc41..615e53b6e 100644 --- a/app/libs/dev_ops/drone/request.rb +++ b/app/libs/dev_ops/drone/request.rb @@ -1,10 +1,4 @@ - # @private class DevOps::Drone::Request - # format :json - # headers 'Accept' => 'application/json' - # parser Proc.new { |body, _| parse(body) } - - # Converts the response body to an ObjectifiedHash. def self.parse(body) body = decode(body) @@ -29,113 +23,70 @@ end end - def get(path, options={}) - set_httparty_config(options) - set_private_token_header(options) - validate self.class.get(path, options) + def get(endpoint, path, options={}) + set_request_defaults(endpoint) + request(:get, endpoint, path, options) end - def post(path, options={}) - set_httparty_config(options) - set_private_token_header(options, path) - validate self.class.post(path, options) + def post(endpoint, path, options={}) + set_request_defaults(endpoint) + request(:post, endpoint, path, options) end - def put(path, options={}) - set_httparty_config(options) - set_private_token_header(options) - validate self.class.put(path, options) + def put(endpoint, path, options={}) + set_request_defaults(endpoint) + request(:put, endpoint, path, options) end - def delete(path, options={}) - set_httparty_config(options) - set_private_token_header(options) - validate self.class.delete(path, options) - end - - # Checks the response code for common errors. - # Returns parsed response for successful requests. - def validate(response) - # case response.code - # when 400; raise Error::BadRequest.new error_message(response) - # when 401; raise Error::Unauthorized.new error_message(response) - # when 403; raise Error::Forbidden.new error_message(response) - # when 404; raise Error::NotFound.new error_message(response) - # when 405; raise Error::MethodNotAllowed.new error_message(response) - # when 406; raise Error::DataNotAccepted.new error_message(response) - # when 409; raise Error::Conflict.new error_message(response) - # when 500; raise Error::InternalServerError.new error_message(response) - # when 502; raise Error::BadGateway.new error_message(response) - # when 503; raise Error::ServiceUnavailable.new error_message(response) - # end - - response.parsed_response - end - - # Sets a base_uri and default_params for requests. - # @raise [Error::MissingCredentials] if endpoint not set. - def set_request_defaults(endpoint, private_token, sudo=nil) - raise Error::MissingCredentials.new("Please set an endpoint to API") unless endpoint - @private_token = private_token - - self.class.base_uri endpoint - self.class.default_params :sudo => sudo - self.class.default_params.delete(:sudo) if sudo.nil? - end - - def request(method, domain, url, **params) - Rails.logger.info("[drone] request: #{method} #{url} #{params.except(:secret).inspect}") - - client = Faraday.new(url: domain) - response = client.public_send(method, url, params) - result = JSON.parse(response.body) - - Rails.logger.info("[drone] response:#{response.status} #{result.inspect}") - - if response.status != 200 - raise DevOps::Drone::Error.parse(result) - end - - if result['errcode'].present? && result['errcode'].to_i.nonzero? - raise DevOps::Drone::Error.parse(result) - end - - result + def delete(endpoint, path, options={}) + set_request_defaults(endpoint) + request(:delete, endpoint, path, options) end private - def conn(auth={}) - token = auth[:token] - puts "[gitea] token: #{token}" + def request(method, endpoint, path, **params) + Rails.logger.info("[drone] request: #{method} #{path} #{params.except(:secret).inspect}") - @client ||= begin - Faraday.new(url: domain) do |req| - req.request :url_encoded - req.headers['Content-Type'] = 'application/json' - req.response :logger # 显示日志 - req.adapter Faraday.default_adapter - req.authorization :Bearer, token - req.headers['Authorization'] - end + client = Faraday.new(path: domain) + response = client.public_send(method, path, params) + result = JSON.parse(response.body) + + Rails.logger.info("[drone] response:#{response.status} #{result.inspect}") + + if response.status != 200 + raise DevOps::Drone::Error.parse(result) end - @client + + if result['errcode'].present? && result['errcode'].to_i.nonzero? + raise DevOps::Drone::Error.parse(result) + end + + result end - # Sets a PRIVATE-TOKEN header for requests. - # @raise [Error::MissingCredentials] if private_token not set. - def set_private_token_header(options, path=nil) - unless path == '/session' - raise Error::MissingCredentials.new("Please set a private_token for user") unless @private_token - options[:headers] = {'PRIVATE-TOKEN' => @private_token} - end + # Sets a base_uri and default_params for requests. + # @raise [Error::MissingCredentials] if endpoint not set. + def set_request_defaults(endpoint, private_token, sudo=nil) + raise "Please set an endpoint to API" unless endpoint end - # Set HTTParty configuration - # @see https://github.com/jnunemaker/httparty - def set_httparty_config(options) - if self.httparty - options.merge!(self.httparty) - end + # Checks the response code for common errors. + # Returns parsed response for successful requests. + def validate(response) + # case response.code + # when 400; raise Error::BadRequest.new error_message(response) + # when 401; raise Error::Unauthorized.new error_message(response) + # when 403; raise Error::Forbidden.new error_message(response) + # when 404; raise Error::NotFound.new error_message(response) + # when 405; raise Error::MethodNotAllowed.new error_message(response) + # when 406; raise Error::DataNotAccepted.new error_message(response) + # when 409; raise Error::Conflict.new error_message(response) + # when 500; raise Error::InternalServerError.new error_message(response) + # when 502; raise Error::BadGateway.new error_message(response) + # when 503; raise Error::ServiceUnavailable.new error_message(response) + # end + + response.parsed_response end def error_message(response) diff --git a/app/models/dev_ops/cloud_account.rb b/app/models/dev_ops/cloud_account.rb index 255396493..778335fb6 100644 --- a/app/models/dev_ops/cloud_account.rb +++ b/app/models/dev_ops/cloud_account.rb @@ -1,6 +1,7 @@ class DevOps::CloudAccount < ApplicationRecord belongs_to :project belongs_to :user + belongs_to :repository def drone_host [drone_ip, ":80"].join diff --git a/app/models/repository.rb b/app/models/repository.rb index 6d20afce5..ec6232927 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -3,6 +3,7 @@ class Repository < ApplicationRecord belongs_to :project, :touch => true belongs_to :user has_one :mirror, foreign_key: :repo_id + has_one :dev_ops_cloud_account, foreign_key: :repo_id has_many :version_releases, dependent: :destroy validates :identifier, presence: true diff --git a/config/routes.rb b/config/routes.rb index 075ed74a0..709ff9073 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -22,7 +22,15 @@ Rails.application.routes.draw do get :common end end - resources :builds + + resources :builds, only: :index do + collection do + get ':number', to: 'builds#detail', as: 'detail' + get ':number/logs/:stage/:step', to: 'builds#detail', as: 'logs' + post ':number', to: 'builds#restart', as: 'restart' + delete ':number', to: 'builds#delete', as: 'delete' + end + end end resources :sync_forge, only: [:create] do diff --git a/db/migrate/20200715075831_add_repository_ref_to_dev_ops_cloud_account.rb b/db/migrate/20200715075831_add_repository_ref_to_dev_ops_cloud_account.rb new file mode 100644 index 000000000..af42232e0 --- /dev/null +++ b/db/migrate/20200715075831_add_repository_ref_to_dev_ops_cloud_account.rb @@ -0,0 +1,7 @@ +class AddRepositoryRefToDevOpsCloudAccount < ActiveRecord::Migration[5.2] + def change + add_column :dev_ops_cloud_accounts, :repo_id, :integer + + add_index :dev_ops_cloud_accounts, :repo_id, name: 'dev_ops_cloud_accounts_repo_id_ix' + end +end