| @@ -3520,6 +3520,7 @@ http://localhost:3000/api/Jason/forge/builds | jq | |||||
| |page |否|string |页数,第几页 | | |page |否|string |页数,第几页 | | ||||
| |limit |否|string |每页多少条数据,默认20条 | | |limit |否|string |每页多少条数据,默认20条 | | ||||
| |search |是|string |构建状态条件过滤; 值说明:pending: 准备中,failure: 构建失败,running: 运行中,error:构建失败(.trustie-pipeline.yml文件错误),success: 构建成功,killed: 撤销构建 | | |search |是|string |构建状态条件过滤; 值说明:pending: 准备中,failure: 构建失败,running: 运行中,error:构建失败(.trustie-pipeline.yml文件错误),success: 构建成功,killed: 撤销构建 | | ||||
| |branch |是|string |分支 | | |||||
| *返回参数说明:* | *返回参数说明:* | ||||
| @@ -4042,13 +4043,15 @@ http://localhost:3000/api/ci/pipelines/list.json?identifier="xxx" | jq | |||||
| *返回参数说明:* | *返回参数说明:* | ||||
| | 参数名 | 类型 | 说明 | | |||||
| | ------------- | ------ | --------------- | | |||||
| | id | int | 流水线id | | |||||
| | pipeline_name | string | 流水线名称 | | |||||
| | file_name | string | 流水线文件名 | | |||||
| | created_at | string | 创建时间 | | |||||
| | sync | int | 是否同步到gitea | | |||||
| | 参数名 | 类型 | 说明 | | |||||
| | ----------------- | ------ | ------------ | | |||||
| | id | int | 流水线id | | |||||
| | pipeline_name | string | 流水线名称 | | |||||
| | file_name | string | 流水线文件名 | | |||||
| | branch | string | 触发分支 | | |||||
| | event | string | 触发事件 | | |||||
| | last_build_time | string | 上次构建时间 | | |||||
| | last_build_status | string | 上次构建状态 | | |||||
| 返回值 | 返回值 | ||||
| @@ -4056,11 +4059,15 @@ http://localhost:3000/api/ci/pipelines/list.json?identifier="xxx" | jq | |||||
| { | { | ||||
| "pipelines": [ | "pipelines": [ | ||||
| { | { | ||||
| "id": 1, | |||||
| "pipeline_name": "2020-01-08 流水线", | |||||
| "file_name": ".trustie.pipeline.yaml", | |||||
| "created_at": "2021-01-08 04:16:24", | |||||
| "updated_at": "2021-01-08 04:16:24" | |||||
| "id": 65, | |||||
| "pipeline_name": "流水线 2021-01-25", | |||||
| "file_name": ".drone.yml", | |||||
| "branch": "develop", | |||||
| "event": "push", | |||||
| "sha": "19fb5eb28603a4a1ec799ad44c1a3ef69d5c2cd0", | |||||
| "identifier": "trustieTest", | |||||
| "last_build_status": "success", | |||||
| "last_build_time": "2021-01-25 15:54:22" | |||||
| } | } | ||||
| ] | ] | ||||
| } | } | ||||
| @@ -4082,7 +4089,10 @@ curl --location --request POST 'http://localhost:3000/api/ci/pipelines' \ | |||||
| --data-raw ' { | --data-raw ' { | ||||
| "pipeline_name": "流水线 2021-01-12", | "pipeline_name": "流水线 2021-01-12", | ||||
| "file_name": ".trustie.pipeline.yaml", | "file_name": ".trustie.pipeline.yaml", | ||||
| "identifier": "xxx" | |||||
| "repo": "xxx", | |||||
| "owner": "xxx", | |||||
| "branch": "master", | |||||
| "event": "push" | |||||
| }' | }' | ||||
| ``` | ``` | ||||
| @@ -4092,7 +4102,10 @@ curl --location --request POST 'http://localhost:3000/api/ci/pipelines' \ | |||||
| | ------------- | ---- | ------ | ---------------------------------------------- | | | ------------- | ---- | ------ | ---------------------------------------------- | | ||||
| | pipeline_name | 是 | string | 流水线名称 | | | pipeline_name | 是 | string | 流水线名称 | | ||||
| | file_name | 是 | string | 文件名称(默认初始值:.trustie.pipeline.yaml) | | | file_name | 是 | string | 文件名称(默认初始值:.trustie.pipeline.yaml) | | ||||
| | identifier | 是 | string | 项目identifier | | |||||
| | repo | 是 | string | 项目identifier | | |||||
| | owner | 是 | string | 项目的owner | | |||||
| | branch | 否 | string | 分支名称, branch必须存在一个 | | |||||
| | event | 是 | string | 触发事件,可多选,多个逗号隔开 | | |||||
| *返回参数说明:* | *返回参数说明:* | ||||
| @@ -4633,6 +4646,192 @@ http://localhost:3000/api/ci/templates/templates_by_stage.json?stage_type=build | |||||
| ------ | ------ | ||||
| #### 模板列表查询 | |||||
| ``` | |||||
| GET /api/ci/templates/list.json?limit=10&page=1&name=&stage_type=customize | |||||
| ``` | |||||
| *示例* | |||||
| ```bash | |||||
| curl --location --request GET 'http://localhost:3000/api/ci/templates/list.json?limit=10&page=1&name=&stage_type=customize' | |||||
| ``` | |||||
| *请求参数说明:* | |||||
| | 参数名 | 必选 | 类型 | 说明 | | |||||
| | ---------- | ---- | ------ | ----------------------------------------- | | |||||
| | stage_type | 是 | string | 阶段类型:init/build/deploy/customize/all | | |||||
| | limit | 是 | int | 每页条数 | | |||||
| | page | 是 | int | 页码 | | |||||
| | name | 否 | string | 模糊查询参数 | | |||||
| *返回参数说明:* | |||||
| | 参数名 | 类型 | 说明 | | |||||
| | ------------- | ------ | ---------------- | | |||||
| | category | string | 分类名称 | | |||||
| | templates | arr | 分类下的模板列表 | | |||||
| | id | int | 模板id | | |||||
| | template_name | string | 模板名称 | | |||||
| | content | String | 模板内容 | | |||||
| 返回值 | |||||
| ```json | |||||
| { | |||||
| "total_count": 1, | |||||
| "templates": [ | |||||
| { | |||||
| "id": 19, | |||||
| "template_name": "工具1", | |||||
| "stage_type": "customize", | |||||
| "category": "其他", | |||||
| "content": "xxxxxxxxxxxxxxxxxxxxxx", | |||||
| "login": "victor", | |||||
| "created_at": "2021-01-26T15:51:30.000+08:00", | |||||
| "updated_at": "2021-01-26T15:51:30.000+08:00" | |||||
| } | |||||
| ] | |||||
| } | |||||
| ``` | |||||
| ------ | |||||
| #### 模板详情查询 | |||||
| ``` | |||||
| GET /api/ci/templates/id | |||||
| ``` | |||||
| *示例* | |||||
| ```bash | |||||
| curl --location --request GET 'http://localhost:3000/api/ci/templates/17.json' | |||||
| ``` | |||||
| *请求参数说明:* | |||||
| | 参数名 | 必选 | 类型 | 说明 | | |||||
| | ------ | ---- | ---- | ------ | | |||||
| | id | 是 | int | 模板id | | |||||
| *返回参数说明:* | |||||
| | 参数名 | 类型 | 说明 | | |||||
| | ------------- | ------ | -------- | | |||||
| | category | string | 分类名称 | | |||||
| | id | int | 模板id | | |||||
| | template_name | string | 模板名称 | | |||||
| | content | String | 模板内容 | | |||||
| 返回值 | |||||
| ```json | |||||
| { | |||||
| "id": 17, | |||||
| "template_name": "win/x86_64", | |||||
| "stage_type": "init", | |||||
| "category": "初始化", | |||||
| "content": "kind: pipeline\r\ntype: docker\r\nname: default\r\nplatform:\r\n os: linux\r\n arch: amd64", | |||||
| "login": "victor", | |||||
| "created_at": "2021-01-26T15:29:27.000+08:00", | |||||
| "updated_at": "2021-01-26T15:29:27.000+08:00" | |||||
| } | |||||
| ``` | |||||
| ------ | |||||
| #### 模板新增/更新 | |||||
| ``` | |||||
| POST /api/ci/templates | |||||
| ``` | |||||
| *示例* | |||||
| ```bash | |||||
| curl --location --request POST 'http://localhost:3000/api/ci/templates' \ | |||||
| --data-raw ' { | |||||
| "template_name": "java++", | |||||
| "stage_type": "build", | |||||
| "category": "java", | |||||
| "content": "xxxxxxxxxxxxxxxxxxxxxx", | |||||
| "id": 21 | |||||
| }' | |||||
| ``` | |||||
| *请求参数说明:* | |||||
| | 参数名 | 必选 | 类型 | 说明 | | |||||
| | ------------- | ---- | ------ | ---------------- | | |||||
| | template_name | 是 | string | 模板名称 | | |||||
| | stage_type | 是 | string | 阶段类型 | | |||||
| | category | 是 | string | 分类 | | |||||
| | content | 是 | string | 模板内容 | | |||||
| | id | 否 | int | 模板id,更新时传 | | |||||
| *返回参数说明:* | |||||
| | 参数名 | 类型 | 说明 | | |||||
| | ------- | ------ | ------------ | | |||||
| | status | int | 状态码 0成功 | | |||||
| | message | string | 消息 | | |||||
| 返回值 | |||||
| ```json | |||||
| { | |||||
| "status": 0, | |||||
| "message": "success" | |||||
| } | |||||
| ``` | |||||
| ------ | |||||
| #### 模板删除 | |||||
| ``` | |||||
| DELETE /api/ci/templates/{id} | |||||
| ``` | |||||
| *示例* | |||||
| ```bash | |||||
| curl --location --request DELETE 'http://localhost:3000/api/ci/templates/10' | |||||
| ``` | |||||
| *请求参数说明:* | |||||
| | 参数名 | 必选 | 类型 | 说明 | | |||||
| | ------ | ---- | ---- | -------- | | |||||
| | id | 是 | int | 流水线id | | |||||
| *返回参数说明:* | |||||
| | 参数名 | 类型 | 说明 | | |||||
| | ------- | ------ | ------------ | | |||||
| | status | int | 状态码 0成功 | | |||||
| | message | string | 返回消息 | | |||||
| 返回值 | |||||
| ```json | |||||
| { | |||||
| "status": 0, | |||||
| "message": "success" | |||||
| } | |||||
| ``` | |||||
| ------ | |||||
| ------ | |||||
| #### 解除CI服务器绑定 | #### 解除CI服务器绑定 | ||||
| ``` | ``` | ||||
| @@ -16,6 +16,10 @@ class Ci::BaseController < ApplicationController | |||||
| @repos = Ci::Repo.find_all_with_namespace(namespace) | @repos = Ci::Repo.find_all_with_namespace(namespace) | ||||
| end | end | ||||
| def load_repo_by_repo_slug(slug) | |||||
| @repo_slug = Ci::Repo.load_repo_by_repo_slug(slug) | |||||
| end | |||||
| private | private | ||||
| def authorize_access_project! | def authorize_access_project! | ||||
| unless @project.manager?(current_user) | unless @project.manager?(current_user) | ||||
| @@ -38,7 +38,7 @@ class Ci::CloudAccountsController < Ci::BaseController | |||||
| ActiveRecord::Base.transaction do | ActiveRecord::Base.transaction do | ||||
| if @repo | if @repo | ||||
| return render_error('该项目已经激活') if @repo.repo_active? | return render_error('该项目已经激活') if @repo.repo_active? | ||||
| @repo.activate!(@ci_user.user_id) | |||||
| @repo.activate!(@project) | |||||
| else | else | ||||
| @repo = Ci::Repo.auto_create!(@ci_user, @project) | @repo = Ci::Repo.auto_create!(@ci_user, @project) | ||||
| @user.update_column(:user_syncing, false) | @user.update_column(:user_syncing, false) | ||||
| @@ -1,18 +1,37 @@ | |||||
| class Ci::PipelinesController < Ci::BaseController | class Ci::PipelinesController < Ci::BaseController | ||||
| before_action :require_login, only: %i[list create] | before_action :require_login, only: %i[list create] | ||||
| skip_before_action :connect_to_ci_db | |||||
| before_action :load_project, only: %i[content create_trustie_pipeline] | |||||
| before_action :load_repository, only: %i[create_trustie_pipeline] | |||||
| skip_before_action :connect_to_ci_db, except: %i[list create destroy] | |||||
| before_action :load_project, only: %i[create] | |||||
| before_action :load_repo, only: %i[create] | |||||
| # ======流水线相关接口========== # | # ======流水线相关接口========== # | ||||
| def list | def list | ||||
| @pipelines = Ci::Pipeline.where('identifier=?', params[:identifier]) | |||||
| @result = Array.new | |||||
| list = Ci::Pipeline.where('identifier=?', params[:identifier]) | |||||
| # 查询build状态 | |||||
| list = list.collect do |pipeline| | |||||
| repo = load_repo_by_repo_slug("#{pipeline.login}/#{pipeline.identifier}") | |||||
| build = repo.builds.order("build_created desc").find_by(build_target: pipeline.branch) | |||||
| if build | |||||
| pipeline.pipeline_status = build.build_status | |||||
| pipeline.last_build_time = Time.at(build.build_created) | |||||
| end | |||||
| @result.push(pipeline) | |||||
| end | |||||
| @total_count = @result.size | |||||
| @pipelines = paginate @result | |||||
| end | end | ||||
| def create | def create | ||||
| ActiveRecord::Base.transaction do | ActiveRecord::Base.transaction do | ||||
| pipeline = Ci::Pipeline.new(pipeline_name: params[:pipeline_name], file_name: params[:file_name], login: current_user.login, identifier: params[:identifier]) | |||||
| size = Ci::Pipeline.where('branch=? and identifier=?', params[:branch], params[:repo]).size | |||||
| if size > 0 | |||||
| render_error("#{params[:branch]}分支已经存在流水线!") | |||||
| return | |||||
| end | |||||
| pipeline = Ci::Pipeline.new(pipeline_name: params[:pipeline_name], file_name: params[:file_name], | |||||
| login: current_user.login, identifier: params[:repo], branch: params[:branch], event: params[:event]) | |||||
| pipeline.save! | pipeline.save! | ||||
| # 默认创建四个初始阶段 | # 默认创建四个初始阶段 | ||||
| @@ -26,12 +45,70 @@ class Ci::PipelinesController < Ci::BaseController | |||||
| ).save! | ).save! | ||||
| index += 1 | index += 1 | ||||
| end | end | ||||
| create_pipeline_file(pipeline) | |||||
| create_ci_repo(pipeline) | |||||
| render_ok({id: pipeline.id}) | render_ok({id: pipeline.id}) | ||||
| end | end | ||||
| rescue Exception => ex | rescue Exception => ex | ||||
| render_error(ex.message) | render_error(ex.message) | ||||
| end | end | ||||
| # 在代码库创建文件 | |||||
| def create_pipeline_file(pipeline) | |||||
| sha = get_pipeline_file_sha(pipeline.file_name, pipeline.branch) | |||||
| if sha | |||||
| logger.info "#{pipeline.file_name}已存在" | |||||
| pipeline.update!(sync: 1, sha: sha) | |||||
| else | |||||
| interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params) | |||||
| if interactor.success? | |||||
| logger.info "#{pipeline.file_name}创建成功" | |||||
| pipeline.update!(sync: 1, sha: interactor.result['content']['sha']) | |||||
| end | |||||
| end | |||||
| end | |||||
| # 在drone数据库repo表新增一条repo记录 | |||||
| def create_ci_repo(pipeline) | |||||
| create_params = { | |||||
| repo_user_id: @ci_user.user_id, | |||||
| repo_namespace: @project.owner.login, | |||||
| repo_name: @project.identifier, | |||||
| repo_slug: "#{@project.owner.login}/#{@project.identifier}-" + pipeline.id.to_s, | |||||
| repo_clone_url: @project.repository.url, | |||||
| repo_branch: pipeline.branch, | |||||
| repo_config: pipeline.file_name | |||||
| } | |||||
| repo = Ci::Repo.create_repo(create_params) | |||||
| repo | |||||
| end | |||||
| def get_pipeline_file_sha(file_name, branch) | |||||
| file_path_uri = URI.parse(file_name) | |||||
| interactor = Repositories::EntriesInteractor.call(@project.owner, @project.identifier, file_path_uri, ref: branch || 'master') | |||||
| if interactor.success? | |||||
| file = interactor.result | |||||
| return file['sha'] | |||||
| else | |||||
| return nil | |||||
| end | |||||
| end | |||||
| def content_params | |||||
| { | |||||
| filepath: params[:file_name], | |||||
| branch: params[:branch], | |||||
| new_branch: params[:new_branch], | |||||
| content: "#pipeline \n", | |||||
| message: 'create pipeline', | |||||
| committer: { | |||||
| email: current_user.mail, | |||||
| name: current_user.login | |||||
| }, | |||||
| identifier: params[:repo] | |||||
| } | |||||
| end | |||||
| def update | def update | ||||
| pipeline = Ci::Pipeline.find(params[:id]) | pipeline = Ci::Pipeline.find(params[:id]) | ||||
| if pipeline | if pipeline | ||||
| @@ -45,6 +122,10 @@ class Ci::PipelinesController < Ci::BaseController | |||||
| def destroy | def destroy | ||||
| pipeline = Ci::Pipeline.find(params[:id]) | pipeline = Ci::Pipeline.find(params[:id]) | ||||
| if pipeline | if pipeline | ||||
| repo = load_repo_by_repo_slug("#{pipeline.login}/#{pipeline.identifier}-" + pipeline.id.to_s) | |||||
| if repo | |||||
| repo.destroy! | |||||
| end | |||||
| pipeline.destroy! | pipeline.destroy! | ||||
| end | end | ||||
| render_ok | render_ok | ||||
| @@ -53,10 +134,9 @@ class Ci::PipelinesController < Ci::BaseController | |||||
| end | end | ||||
| def content | def content | ||||
| @yaml = "#pipeline \n" | |||||
| @yaml = "\n" | |||||
| pipeline = Ci::Pipeline.find(params[:id]) | pipeline = Ci::Pipeline.find(params[:id]) | ||||
| @sync = pipeline.sync | |||||
| @sha = '' | |||||
| @sha = pipeline.sha | |||||
| stages = pipeline.pipeline_stages | stages = pipeline.pipeline_stages | ||||
| if stages && !stages.empty? | if stages && !stages.empty? | ||||
| init_step = stages.first.pipeline_stage_steps.first | init_step = stages.first.pipeline_stage_steps.first | ||||
| @@ -72,55 +152,13 @@ class Ci::PipelinesController < Ci::BaseController | |||||
| end | end | ||||
| end | end | ||||
| end | end | ||||
| if @sync == 1 | |||||
| @sha = get_pipeline_file_sha(pipeline.file_name) | |||||
| trigger = '' | |||||
| trigger += " branch:\r\n - #{pipeline.branch}\r\n" unless pipeline.branch.blank? | |||||
| unless pipeline.event.blank? | |||||
| trigger += " event:\r\n" | |||||
| pipeline.event.split(',').each { |event| trigger += " - #{event}\r\n"} | |||||
| end | end | ||||
| end | |||||
| def get_pipeline_file_sha(file_name) | |||||
| file_path_uri = URI.parse(file_name) | |||||
| interactor = Repositories::EntriesInteractor.call(@project.owner, @project.identifier, file_path_uri, ref: params[:ref] || "master") | |||||
| if interactor.success? | |||||
| file = interactor.result | |||||
| return file['sha'] | |||||
| end | |||||
| end | |||||
| def create_trustie_pipeline | |||||
| pipeline = Ci::Pipeline.find(params[:id]) | |||||
| sha = get_pipeline_file_sha(pipeline.file_name) | |||||
| if sha | |||||
| pipeline.update!(sync: 1) | |||||
| interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, params[:owner], params.merge(identifier: @project.identifier,sha: sha)) | |||||
| if interactor.success? | |||||
| render_ok | |||||
| else | |||||
| render_error(interactor.error) | |||||
| end | |||||
| else | |||||
| interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params) | |||||
| if interactor.success? | |||||
| pipeline.update!(sync: 1) | |||||
| render_ok | |||||
| else | |||||
| render_error(interactor.error) | |||||
| end | |||||
| end | |||||
| end | |||||
| def content_params | |||||
| { | |||||
| filepath: params[:filepath], | |||||
| branch: params[:branch], | |||||
| new_branch: params[:new_branch], | |||||
| content: params[:content], | |||||
| message: params[:message], | |||||
| committer: { | |||||
| email: current_user.mail, | |||||
| name: current_user.login | |||||
| }, | |||||
| identifier: @project.identifier | |||||
| } | |||||
| @yaml += "trigger:\r\n" + trigger unless trigger.blank? | |||||
| end | end | ||||
| # =========阶段相关接口========= # | # =========阶段相关接口========= # | ||||
| @@ -135,8 +173,8 @@ class Ci::PipelinesController < Ci::BaseController | |||||
| # 修改stage排序 | # 修改stage排序 | ||||
| update_stage_index(params[:id], params[:show_index], 1) | update_stage_index(params[:id], params[:show_index], 1) | ||||
| pipeline_stage = Ci::PipelineStage.new(stage_name: params[:stage_name], | pipeline_stage = Ci::PipelineStage.new(stage_name: params[:stage_name], | ||||
| stage_type: params[:stage_type].blank? ? 'customize' : params[:stage_type], | |||||
| pipeline_id: params[:id], show_index: params[:show_index]) | |||||
| stage_type: params[:stage_type].blank? ? 'customize' : params[:stage_type], | |||||
| pipeline_id: params[:id], show_index: params[:show_index]) | |||||
| pipeline_stage.save! | pipeline_stage.save! | ||||
| render_ok | render_ok | ||||
| end | end | ||||
| @@ -188,7 +226,7 @@ class Ci::PipelinesController < Ci::BaseController | |||||
| unless steps.empty? | unless steps.empty? | ||||
| steps.each do |step| | steps.each do |step| | ||||
| unless step[:template_id] | unless step[:template_id] | ||||
| render_error("请选择模板!") | |||||
| render_error('请选择模板!') | |||||
| return | return | ||||
| end | end | ||||
| if !step[:id] | if !step[:id] | ||||
| @@ -41,11 +41,8 @@ class Ci::ProjectsController < Ci::BaseController | |||||
| ActiveRecord::Base.transaction do | ActiveRecord::Base.transaction do | ||||
| if @repo | if @repo | ||||
| return render_error('该项目已经激活') if @repo.repo_active? | return render_error('该项目已经激活') if @repo.repo_active? | ||||
| if @project.ci_reactivate? | |||||
| @project.ci_reactivate!(@repo) | |||||
| return render_ok | |||||
| end | |||||
| @repo.activate!(@ci_user.user_id) | |||||
| @repo.activate!(@project) | |||||
| return render_ok | |||||
| else | else | ||||
| @repo = Ci::Repo.auto_create!(@ci_user, @project) | @repo = Ci::Repo.auto_create!(@ci_user, @project) | ||||
| @ci_user.update_column(:user_syncing, false) | @ci_user.update_column(:user_syncing, false) | ||||
| @@ -66,7 +63,7 @@ class Ci::ProjectsController < Ci::BaseController | |||||
| return render_error('该项目已经取消激活') if !@repo.repo_active? | return render_error('该项目已经取消激活') if !@repo.repo_active? | ||||
| @project.update_column(:open_devops, false) | @project.update_column(:open_devops, false) | ||||
| @repo.deactivate! | |||||
| @repo.deactivate_repos! | |||||
| render_ok | render_ok | ||||
| end | end | ||||
| @@ -1,30 +1,53 @@ | |||||
| class Ci::TemplatesController < ApplicationController | |||||
| class Ci::TemplatesController < Ci::BaseController | |||||
| def list | |||||
| @templates = Ci::Template.all | |||||
| end | |||||
| before_action :require_login, only: %i[list create] | |||||
| skip_before_action :connect_to_ci_db | |||||
| def templates_by_stage | |||||
| #======模板管理======# | |||||
| def list | |||||
| stage_type = params[:stage_type] | stage_type = params[:stage_type] | ||||
| if stage_type != Ci::PipelineStage::CUSTOMIZE_STAGE_TYPE | |||||
| @templates = Ci::Template.where("stage_type = ?", stage_type) | |||||
| # 根据模板类别分组 | |||||
| @category_templates = @templates.group_by{ |template| template.category } | |||||
| else | |||||
| # 自定义阶段,按阶段分类分类返回模板列表 | |||||
| @templates = Ci::Template.where("stage_type != ?", Ci::PipelineStage::INIT_STAGE_TYPE) | |||||
| @category_templates = @templates.group_by{ |template| template.parent_category } | |||||
| template_name = params[:name] | |||||
| templates = template_name.blank? ? Ci::Template.all : Ci::Template.where("template_name like ?", "%#{template_name}%") | |||||
| templates = templates.select{ |template| template.login == current_user.login} unless current_user.admin? | |||||
| if !stage_type.blank? && stage_type != 'all' | |||||
| templates = templates.select{ |template| template.stage_type == stage_type} | |||||
| end | end | ||||
| @total_count = templates.map(&:id).count | |||||
| @templates = paginate templates | |||||
| end | |||||
| def show | |||||
| @template = Ci::Template.find(params[:id]) | |||||
| end | end | ||||
| def create | def create | ||||
| template = Ci::Template.new(template_name: params[:template_name], | |||||
| stage_type: params[:stage_type], | |||||
| category: params[:category], | |||||
| parent_category: params[:parent_category], | |||||
| content: params[:content] | |||||
| ) | |||||
| template.save! | |||||
| stage_type = params[:stage_type] | |||||
| category = params[:category] | |||||
| if category.blank? | |||||
| category = Ci::Template::STAGE_TYPES[:"#{stage_type}"] | |||||
| end | |||||
| if params[:id] | |||||
| template = Ci::Template.find(params[:id]) | |||||
| if template | |||||
| template.update!(template_name: params[:template_name], | |||||
| stage_type: stage_type, | |||||
| category: category, | |||||
| parent_category: Ci::Template::STAGE_TYPES[:"#{stage_type}"], | |||||
| content: params[:content], | |||||
| login: current_user.admin? ? 'admin' : current_user.login | |||||
| ) | |||||
| end | |||||
| else | |||||
| template = Ci::Template.new(template_name: params[:template_name], | |||||
| stage_type: stage_type, | |||||
| category: category, | |||||
| parent_category: Ci::Template::STAGE_TYPES[:"#{stage_type}"], | |||||
| content: params[:content], | |||||
| login: current_user.admin? ? 'admin' : current_user.login | |||||
| ) | |||||
| template.save! | |||||
| end | |||||
| render_ok | render_ok | ||||
| rescue Exception => ex | rescue Exception => ex | ||||
| render_error(ex.message) | render_error(ex.message) | ||||
| @@ -53,4 +76,20 @@ class Ci::TemplatesController < ApplicationController | |||||
| render_error(ex.message) | render_error(ex.message) | ||||
| end | end | ||||
| #======流水线模板查询=====# | |||||
| def templates_by_stage | |||||
| stage_type = params[:stage_type] | |||||
| if stage_type != Ci::PipelineStage::CUSTOMIZE_STAGE_TYPE | |||||
| @templates = Ci::Template.where("stage_type = ?", stage_type) | |||||
| @templates = @templates.select{ |template| template.login == current_user.login || template.login == 'admin'} unless current_user.admin? | |||||
| # 根据模板类别分组 | |||||
| @category_templates = @templates.group_by{ |template| template.category } | |||||
| else | |||||
| # 自定义阶段,按阶段分类分类返回模板列表 | |||||
| @templates = Ci::Template.where("stage_type != ?", Ci::PipelineStage::INIT_STAGE_TYPE) | |||||
| @templates = @templates.select{ |template| template.login == current_user.login || template.login == 'admin'} unless current_user.admin? | |||||
| @category_templates = @templates.group_by{ |template| template.parent_category } | |||||
| end | |||||
| end | |||||
| end | end | ||||
| @@ -101,9 +101,6 @@ module Ci::CloudAccountManageable | |||||
| if cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_SELF | if cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_SELF | ||||
| @connection.execute("DROP DATABASE IF EXISTS #{current_user.login}_drone") # TOTO drop drone database | @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 | end | ||||
| cloud_account.destroy! unless cloud_account.blank? | cloud_account.destroy! unless cloud_account.blank? | ||||
| @@ -11,4 +11,6 @@ class Ci::Build < Ci::RemoteBase | |||||
| scope :pending, -> { by_status('pending') } | scope :pending, -> { by_status('pending') } | ||||
| scope :killed, -> { by_status('killed') } | scope :killed, -> { by_status('killed') } | ||||
| scope :by_status, ->(status) { where(build_status: status) } | scope :by_status, ->(status) { where(build_status: status) } | ||||
| scope :by_branch, ->(branch) { where(build_target: branch) } | |||||
| end | end | ||||
| @@ -4,10 +4,10 @@ class Ci::Perm < Ci::RemoteBase | |||||
| belongs_to :user, class_name: 'Ci::User', foreign_key: :perm_user_id | belongs_to :user, class_name: 'Ci::User', foreign_key: :perm_user_id | ||||
| belongs_to :repo, class_name: 'Ci::Repo', foreign_key: :perm_repo_uid | belongs_to :repo, class_name: 'Ci::Repo', foreign_key: :perm_repo_uid | ||||
| def self.auto_create!(user, repo) | |||||
| def self.auto_create!(user_id, repo_id) | |||||
| perm = new( | perm = new( | ||||
| perm_user_id: user.user_id, | |||||
| perm_repo_uid: repo.repo_id, | |||||
| perm_user_id: user_id, | |||||
| perm_repo_uid: repo_id, | |||||
| perm_read: true, | perm_read: true, | ||||
| perm_write: true, | perm_write: true, | ||||
| perm_admin: true, | perm_admin: true, | ||||
| @@ -10,7 +10,10 @@ | |||||
| # pipeline_status :string(50) default("unknown"), not null | # pipeline_status :string(50) default("unknown"), not null | ||||
| # login :string(255) | # login :string(255) | ||||
| # sync :integer default("0"), not null | # sync :integer default("0"), not null | ||||
| # project_id :integer | |||||
| # identifier :string(11) | |||||
| # branch :string(255) | |||||
| # event :string(255) | |||||
| # sha :string(255) | |||||
| # | # | ||||
| class Ci::Pipeline < Ci::LocalBase | class Ci::Pipeline < Ci::LocalBase | ||||
| @@ -20,4 +23,6 @@ class Ci::Pipeline < Ci::LocalBase | |||||
| has_many :pipeline_stages, -> { reorder(show_index: :asc) }, foreign_key: "pipeline_id", :class_name => 'Ci::PipelineStage', dependent: :destroy | has_many :pipeline_stages, -> { reorder(show_index: :asc) }, foreign_key: "pipeline_id", :class_name => 'Ci::PipelineStage', dependent: :destroy | ||||
| attr_accessor :last_build_time | |||||
| end | end | ||||
| @@ -20,37 +20,53 @@ class Ci::Repo < Ci::RemoteBase | |||||
| return repos | return repos | ||||
| end | end | ||||
| def activate!(ci_user_id) | |||||
| update(repo_active: 1, | |||||
| repo_signer: generate_code, | |||||
| repo_secret: generate_code, | |||||
| repo_user_id: ci_user_id, | |||||
| repo_timeout: 60, | |||||
| repo_config: '.trustie-pipeline.yml', | |||||
| repo_updated: Time.now.to_i) | |||||
| def self.load_repo_by_repo_slug(repo_slug) | |||||
| logger.info "########repo_slug: #{repo_slug}" | |||||
| repo = Ci::Repo.where(repo_slug: repo_slug).first | |||||
| return repo | |||||
| end | |||||
| def find_by_repo_name(repo_name) | |||||
| logger.info "########repo_name: #{repo_name}" | |||||
| repos = Ci::Repo.where(repo_name: repo_name) | |||||
| return repos | |||||
| end | end | ||||
| def self.auto_create!(user, project) | def self.auto_create!(user, project) | ||||
| repo = new( | |||||
| create_params = { | |||||
| repo_user_id: user.user_id, | repo_user_id: user.user_id, | ||||
| repo_namespace: project.owner.login, | repo_namespace: project.owner.login, | ||||
| repo_name: project.identifier, | repo_name: project.identifier, | ||||
| repo_slug: "#{project.owner.login}/#{project.identifier}", | repo_slug: "#{project.owner.login}/#{project.identifier}", | ||||
| repo_clone_url: project.repository.url, | |||||
| repo_branch: 'master', | |||||
| repo_config: '.trustie-pipeline.yml' | |||||
| } | |||||
| repo = create_repo(create_params) | |||||
| repo | |||||
| end | |||||
| def self.create_repo(create_params) | |||||
| repo = new( | |||||
| repo_user_id: create_params[:repo_user_id], | |||||
| repo_namespace: create_params[:repo_namespace], | |||||
| repo_name: create_params[:repo_name], | |||||
| repo_slug: create_params[:repo_slug], | |||||
| repo_scm: "git", | repo_scm: "git", | ||||
| repo_ssh_url: "", | repo_ssh_url: "", | ||||
| repo_html_url: "", | repo_html_url: "", | ||||
| repo_clone_url: project.repository.url, | |||||
| repo_clone_url: create_params[:repo_clone_url], | |||||
| repo_active: 1, | repo_active: 1, | ||||
| repo_private: true, | repo_private: true, | ||||
| repo_visibility: 'private', | repo_visibility: 'private', | ||||
| repo_branch: 'master', | |||||
| repo_branch: create_params[:repo_branch], | |||||
| repo_counter: 0, | repo_counter: 0, | ||||
| repo_trusted: false, | repo_trusted: false, | ||||
| repo_protected: false, | repo_protected: false, | ||||
| repo_synced: 0, | repo_synced: 0, | ||||
| repo_version: 1, | repo_version: 1, | ||||
| repo_timeout: 60, | repo_timeout: 60, | ||||
| repo_config: '.trustie-pipeline.yml', | |||||
| repo_config: create_params[:repo_config], | |||||
| repo_created: Time.now.to_i, | repo_created: Time.now.to_i, | ||||
| repo_updated: Time.now.to_i | repo_updated: Time.now.to_i | ||||
| ) | ) | ||||
| @@ -58,13 +74,34 @@ class Ci::Repo < Ci::RemoteBase | |||||
| repo.repo_signer = repo.generate_code | repo.repo_signer = repo.generate_code | ||||
| repo.repo_secret = repo.generate_code | repo.repo_secret = repo.generate_code | ||||
| if repo.save! | if repo.save! | ||||
| Ci::Perm.auto_create!(user, repo) | |||||
| Ci::Perm.auto_create!(create_params[:repo_user_id], repo.id) | |||||
| repo.update_column(:repo_uid, repo.id) | repo.update_column(:repo_uid, repo.id) | ||||
| repo | repo | ||||
| end | end | ||||
| end | end | ||||
| # 取消激活同一个项目(多个repo) | |||||
| def deactivate_repos! | |||||
| repos = find_by_repo_name(self.repo_name) | |||||
| repos.each do |repo| | |||||
| repo.update_column(:repo_active, 0) | |||||
| end | |||||
| end | |||||
| def activate!(project) | |||||
| repos = find_by_repo_name(self.repo_name) | |||||
| project.update_column(:open_devops, true) | |||||
| project.increment!(:open_devops_count) | |||||
| repos.each do |repo| | |||||
| repo.update_column(:repo_active, 1) | |||||
| end | |||||
| end | |||||
| def deactivate! | def deactivate! | ||||
| update_column(:repo_active, 0) | update_column(:repo_active, 0) | ||||
| end | end | ||||
| def destroy! | |||||
| self.destroy | |||||
| end | |||||
| end | end | ||||
| @@ -10,6 +10,7 @@ | |||||
| # created_at :datetime not null | # created_at :datetime not null | ||||
| # updated_at :datetime not null | # updated_at :datetime not null | ||||
| # parent_category :string(255) | # parent_category :string(255) | ||||
| # login :string(255) | |||||
| # | # | ||||
| # Indexes | # Indexes | ||||
| # | # | ||||
| @@ -20,4 +21,7 @@ class Ci::Template < Ci::LocalBase | |||||
| validates :template_name, presence: {message: "模板名称不能为空"} | validates :template_name, presence: {message: "模板名称不能为空"} | ||||
| validates :stage_type, presence: {message: "阶段类型不能为空"} | validates :stage_type, presence: {message: "阶段类型不能为空"} | ||||
| validates :category, presence: {message: "模板类型不能为空"} | validates :category, presence: {message: "模板类型不能为空"} | ||||
| STAGE_TYPES = {init:'初始化',build:'编译构建',deploy:'部署',customize:'其他'} | |||||
| end | end | ||||
| @@ -24,6 +24,9 @@ class Ci::Builds::ListQuery < ApplicationQuery | |||||
| else | else | ||||
| scope | scope | ||||
| end | end | ||||
| builds = scope.by_branch(params[:branch]) if params[:branch] | |||||
| custom_sort(builds, params[:sort_by], params[:sort_direction]) | custom_sort(builds, params[:sort_by], params[:sort_direction]) | ||||
| end | end | ||||
| end | end | ||||
| @@ -1,4 +1,4 @@ | |||||
| json.id user.id | json.id user.id | ||||
| json.name user.real_name | |||||
| json.name user.real_name == '游客' ? '-' : user.real_name | |||||
| json.login user.login | json.login user.login | ||||
| json.image_url url_to_avatar(user) | json.image_url url_to_avatar(user) | ||||
| @@ -1,8 +1,12 @@ | |||||
| json.id pipeline.id | json.id pipeline.id | ||||
| json.pipeline_name pipeline.pipeline_name | json.pipeline_name pipeline.pipeline_name | ||||
| json.pipeline_status pipeline.pipeline_status | |||||
| json.pipeline_status pipeline.pipeline_status == 'unknown' ? '' : pipeline.pipeline_status | |||||
| json.file_name pipeline.file_name | json.file_name pipeline.file_name | ||||
| json.sync pipeline.sync | json.sync pipeline.sync | ||||
| json.branch pipeline.branch | |||||
| json.event pipeline.event | |||||
| json.sha pipeline.sha | |||||
| json.identifier pipeline.identifier | json.identifier pipeline.identifier | ||||
| json.last_build_time pipeline.last_build_time.nil? ? '' : pipeline.last_build_time.strftime("%Y-%m-%d %H:%M:%S") | |||||
| json.created_at pipeline.created_at.strftime("%Y-%m-%d %H:%M:%S") | json.created_at pipeline.created_at.strftime("%Y-%m-%d %H:%M:%S") | ||||
| json.updated_at pipeline.updated_at.strftime("%Y-%m-%d %H:%M:%S") | json.updated_at pipeline.updated_at.strftime("%Y-%m-%d %H:%M:%S") | ||||
| @@ -1,3 +1,4 @@ | |||||
| json.total_count @total_count | |||||
| json.pipelines @pipelines do |pipeline| | json.pipelines @pipelines do |pipeline| | ||||
| json.partial! "/ci/pipelines/list", pipeline: pipeline | json.partial! "/ci/pipelines/list", pipeline: pipeline | ||||
| end | end | ||||
| @@ -3,6 +3,7 @@ json.template_name template.template_name | |||||
| json.stage_type template.stage_type | json.stage_type template.stage_type | ||||
| json.category template.category | json.category template.category | ||||
| json.content template.content | json.content template.content | ||||
| json.login template.login | |||||
| json.created_at template.created_at | json.created_at template.created_at | ||||
| json.updated_at template.updated_at | json.updated_at template.updated_at | ||||
| @@ -1,3 +1,4 @@ | |||||
| json.total_count @total_count | |||||
| json.templates @templates do |template| | json.templates @templates do |template| | ||||
| json.partial! "/ci/templates/list", template: template | json.partial! "/ci/templates/list", template: template | ||||
| end | end | ||||
| @@ -0,0 +1,9 @@ | |||||
| json.id @template.id | |||||
| json.template_name @template.template_name | |||||
| json.stage_type @template.stage_type | |||||
| json.category @template.category | |||||
| json.content @template.content | |||||
| json.login @template.login | |||||
| json.created_at @template.created_at | |||||
| json.updated_at @template.updated_at | |||||
| @@ -32,7 +32,7 @@ Rails.application.routes.draw do | |||||
| end | end | ||||
| end | end | ||||
| resources :templates, only: [:list,:templates_by_stage,:create,:update,:destroy] do | |||||
| resources :templates, only: [:list,:templates_by_stage,:create,:update,:destroy,:show] do | |||||
| collection do | collection do | ||||
| get :list | get :list | ||||
| get :templates_by_stage | get :templates_by_stage | ||||
| @@ -0,0 +1,7 @@ | |||||
| class AddBranchAndEventAndShaToCiPipelines < ActiveRecord::Migration[5.2] | |||||
| def change | |||||
| add_column :ci_pipelines, :branch, :string | |||||
| add_column :ci_pipelines, :event, :string | |||||
| add_column :ci_pipelines, :sha, :string | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,5 @@ | |||||
| class AddLoginToCiTemplates < ActiveRecord::Migration[5.2] | |||||
| def change | |||||
| add_column :ci_templates, :login, :string | |||||
| end | |||||
| end | |||||