diff --git a/api_document.md b/api_document.md index 50a45573c..4d8a6d5ba 100644 --- a/api_document.md +++ b/api_document.md @@ -3865,6 +3865,48 @@ http://localhost:3000/api/users/ci/cloud_account | jq } } ``` +------ + +#### 绑定CI服务器-Trustie提供服务器 + +``` +POST /api/users/ci/cloud_account/trustie_bind +``` + +*示例* + +```bash +curl -X POST \ +-d "account=xx" \ +https://localhost:3000/api/users/ci/cloud_account/trustie_bind.json | jq +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| ------- | ---- | ------ | ---------- | +| account | 是 | string | 登录用户名 | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------------ | ------ | --------------------------------------- | +| step | int | 0: 未绑定;1: 未认证(已绑定),2: 已认证 | +| ip | string | ci服务器ip | +| redirect_url | string | 认证地址 | + +返回值 + +```json +{ + "step": 0, + "cloud_account": { + "ip": "xxx.xxx.xxx.x", + "redirect_url": "http://localhost:3000/login" + } +} +``` + --- #### 绑定CI服务器 @@ -3907,10 +3949,697 @@ https://localhost:3000/api/users/ci/cloud_account/bind.json | jq } } ``` +------ + +#### 流水线查询 + +``` +GET /api/ci/pipelines/list +``` + +*示例* + +```bash +curl -X GET \ +http://localhost:3000/api/ci/pipelines/list.json | jq +``` + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------------- | ------ | ---------------------------------------------- | +| id | int | 流水线id | +| pipeline_name | string | 流水线名称 | +| file_name | string | 流水线文件名 | +| created_at | string | 创建时间 | +| stages | arr | 流水线包含的阶段数组(字段详情看阶段查询接口) | + +返回值 + +```json +{ + "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", + "stages": [ + { + "id": 1, + "stage_name": "初始化", + "stage_type": "init", + "pipeline_id": 1, + "show_index": 0, + "created_at": "2021-01-08 04:16:24", + "updated_at": "2021-01-08 04:16:24" + }, + { + "id": 2, + "stage_name": "编译构建", + "stage_type": "build", + "pipeline_id": 1, + "show_index": 1, + "created_at": "2021-01-08 04:16:24", + "updated_at": "2021-01-11 04:16:24" + } + ] + } + ] +} +``` + --- +#### 流水线新增 -### 解除CI服务器绑定 +点击"新增流水线"按钮时调用。 + +``` +POST /api/ci/pipelines +``` + +*示例* + +```bash +curl --location --request POST 'http://localhost:3000/api/ci/pipelines' \ +--header 'Content-Type: application/json' \ +--data-raw ' { + "pipeline_name": "流水线 2021-01-12", + "file_name": ".trustie.pipeline.yaml" +}' +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| ------------- | ---- | ------ | ---------------------------------------------- | +| pipeline_name | 是 | string | 流水线名称(默认初始值:流水线 yyyy-mm-dd) | +| file_name | 是 | string | 文件名称(默认初始值:.trustie.pipeline.yaml) | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------- | ------ | ------------ | +| status | int | 状态码 0成功 | +| message | string | 返回消息 | + +返回值 + +```json +{ + "status": 0, + "message": "success" +} +``` + +------ + +#### 流水线更新 + +修改流水线名称时调用。 + +``` +PUT /api/ci/pipelines/{id} +``` + +*示例* + +```bash +curl --location --request PUT 'http://localhost:3000/api/ci/pipelines/3' \ +--header 'Content-Type: application/json' \ +--data-raw ' { + "pipeline_name": "2020-01-11 流水线" +}' +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| ------------- | ---- | ------ | ---------- | +| id | 是 | id | 流水线id | +| pipeline_name | 是 | string | 流水线名称 | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------- | ------ | ------------ | +| status | int | 状态码 0成功 | +| message | string | 返回消息 | + +返回值 + +```json +{ + "status": 0, + "message": "success" +} +``` + +------ + +#### 流水线删除 + +``` +DELETE /api/ci/pipelines/{id} +``` + +*示例* + +```bash +curl -X DELETE \ +https://localhost:3000/api/ci/pipelines/1 | jq +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| ------ | ---- | ---- | -------- | +| id | 是 | int | 流水线id | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------- | ------ | ------------ | +| status | int | 状态码 0成功 | +| message | string | 返回消息 | + +返回值 + +```json +{ + "status": 0, + "message": "success" +} +``` + +------ + +#### 流水线阶段排序 + +当新增阶段或者删除阶段时重新给受影响的stage设置show_index。 + +``` +PUT /api/ci/pipelines/{id}/sort_stage +``` + +*示例* + +```bash +curl --location --request PUT 'http://localhost:3000/api/ci/pipelines/1/sort_stage.json' \ +--header 'Content-Type: application/json' \ +--data-raw ' {"stage_index":[ + {"id": 1,"show_index": 0}, + {"id": 2,"show_index": 1}, + {"id": 3,"show_index": 2}, + {"id": 4,"show_index": 3}, + {"id": 7,"show_index": 4} + ] + }' +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| ----------- | ---- | ---- | ---------- | +| stage_index | 是 | arr | 参数数组 | +| id | 是 | int | 阶段id | +| show_index | 是 | int | 阶段的序号 | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------- | ------ | ------------ | +| status | int | 状态码 0成功 | +| message | string | 返回消息 | + +返回值 + +```json +{ + "status": 0, + "message": "success" +} +``` + +------ + +#### 确认阶段流水线内容查询 + +``` +GET /api/ci/pipelines/{id}/content +``` + +*示例* + +```bash +curl -X GET \ +http://localhost:3000/api/ci/pipelines/1/content.json | jq +``` + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------ | ---- | -------- | +| id | int | 流水线id | + +返回值 + +```json +{ + "content": "#pipeline \nkind: pipeline\r\nname: maven项目-镜像仓库\r\n\r\nplatform:\r\n os: linux\r\n arch: arm64\nsteps:\n- name: Maven编译\r\n image: arm64v8/maven\r\n commands:\r\n - mvn install\n- name: 编译镜像-推送到仓库\r\n image: plugins/docker\r\n settings:\r\n username: moshenglv\r\n password: RL9UB5P7Jtzukka\r\n repo: docker.io/moshenglv/demo\r\n tags: latest\n" +} +``` + +------ + +#### 流水线阶段新增 + +``` +POST /api/ci/pipelines/{id}/create_stage +``` + +*示例* + +```bash +curl --location --request POST 'http://localhost:3000/api/ci/pipelines/14/create_stage.json' \ +--header 'Content-Type: application/json' \ +--data-raw ' {"stages":[{ + "stage_name": "新阶段1", + "stage_type": "customize", + "show_index": 5 +}, +{ + "stage_name": "新阶段2", + "stage_type": "customize", + "show_index": 5 +} +] + }' +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| ---------- | ---- | ------ | -------------------------------- | +| stages | 是 | arr | 新增的阶段数组 | +| id | 是 | int | 流水线id | +| stage_name | 是 | string | 阶段名称(默认为 阶段名-模板名) | +| show_index | 是 | int | 阶段排序 | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------- | ------ | ------------ | +| status | int | 状态码 0成功 | +| message | string | 返回消息 | + +返回值 + +```json +{ + "status": 0, + "message": "success" +} +``` + +------ + +#### 流水线阶段更新 + +``` +PUT /api/ci/pipelines/{id}/update_stage +``` + +*示例* + +```bash +curl --location --request PUT 'http://localhost:3000/api/ci/pipelines/1/5/update_stage.json' \ +--header 'Content-Type: application/json' \ +--data-raw ' { + "stage_name": "新阶段-更新", + "stage_type": "customize", + "show_index": 10 +}' +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| ---------- | ---- | ------ | -------------------------------- | +| id | 是 | int | 流水线id | +| stage_name | 是 | string | 阶段名称(默认为 阶段名-模板名) | +| show_index | 是 | int | 阶段排序 | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------- | ------ | ------------ | +| status | int | 状态码 0成功 | +| message | string | 返回消息 | + +返回值 + +```json +{ + "status": 0, + "message": "success" +} +``` + +------ + +#### 流水线阶段删除 + +``` +DELETE /api/ci/pipelines/{id}/{stage_id}/delete_stage +``` + +*示例* + +```bash +curl -X DELETE \ +https://localhost:3000/api/ci/pipelines/1/6/delete_stage.json | jq +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| -------- | ---- | ---- | -------- | +| id | 是 | int | 流水线id | +| stage_id | 是 | int | 阶段id | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------- | ------ | ------------ | +| status | int | 状态码 0成功 | +| message | string | 返回消息 | + +返回值 + +```json +{ + "status": 0, + "message": "success" +} +``` + +------ + +#### 流水线阶段步骤查询 + +``` +GET /api/ci/pipelines/{id}/{stage_id}/steps.json +``` + +*示例* + +```bash +curl -X GET \ +http://localhost:3000/api/ci/pipelines/1/2/steps.json | jq +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| -------- | ---- | ---- | -------- | +| id | 是 | int | 流水线id | +| stage_id | 是 | int | 阶段id | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ----------- | ------ | ---------- | +| id | int | 步骤id | +| step_name | string | 步骤名称 | +| stage_id | int | 所属阶段id | +| template_id | int | 模板id | +| show_index | int | 显示顺序 | +| content | String | 步骤内容 | + +返回值 + +```json +{ + "steps": [ + { + "id": 1, + "step_name": "编译构建-maven", + "stage_id": 2, + "template_id": null, + "show_index": 0, + "content": "xxxxxxxxxxx", + "created_at": "2021-01-11T09:57:17.000+08:00", + "updated_at": "2021-01-11T09:57:17.000+08:00" + }, + { + "id": 2, + "step_name": "编译构建-maven-更新", + "stage_id": 2, + "template_id": 2, + "show_index": 2, + "content": "xxxx====xxxxxxx", + "created_at": "2021-01-11T10:12:58.000+08:00", + "updated_at": "2021-01-11T10:40:54.000+08:00" + } + ] +} +``` + +------ + +#### 流水线阶段步骤新增 + +``` +POST /api/ci/pipelines/{id}/{stage_id}/create_step +``` + +*示例* + +```bash +curl --location --request POST 'http://localhost:3000/api/ci/pipelines/14/20/create_step.json' \ +--header 'Content-Type: application/json' \ +--data-raw ' {"steps":[{ + "step_name": "编译构建-gradle", + "show_index": 1, + "content": "xxxxxxxxxxx", + "template_id":1 +}, +{ + "step_name": "编译构建-maven", + "show_index": 1, + "content": "xxxxxxxxxxx", + "template_id":1 +} +] + }' +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| ----------- | ---- | ------ | ------------------------- | +| steps | 是 | arr | 需要新增的步骤数组 | +| id | 是 | int | 流水线id | +| stage_id | 是 | int | 阶段id | +| step_name | 是 | string | 阶段名称(阶段名-模板名) | +| content | 是 | string | 步骤内容 | +| template_id | 是 | int | 模板id | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------- | ------ | ------------ | +| status | int | 状态码 0成功 | +| message | string | 返回消息 | + +返回值 + +```json +{ + "status": 0, + "message": "success" +} +``` + +------ + +#### 流水线阶段步骤更新 + +``` +PUT /api/ci/pipelines/{id}/{stage_id}/update_step +``` + +*示例* + +```bash +curl --location --request PUT 'http://localhost:3000/api/ci/pipelines/1/2/update_step.json' \ +--header 'Content-Type: application/json' \ +--data-raw ' {"steps":[{ + "id":7, + "step_name": "编译构建11-gradle", + "show_index": 1, + "content": "xxxxxxxxxxx", + "template_id":2 +}, +{ + "id":8, + "step_name": "编译构建22-maven", + "show_index": 1, + "content": "xxxxxxxxxxx", + "template_id":2 +} +] + }' +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| ----------- | ---- | ------ | ------------------------- | +| steps | 是 | arr | 需要更新step数组 | +| id | 是 | int | 流水线id | +| stage_id | 是 | int | 阶段id | +| step_name | 是 | string | 阶段名称(阶段名-模板名) | +| content | 是 | string | 步骤内容 | +| template_id | 是 | int | 模板id | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------- | ------ | ------------ | +| status | int | 状态码 0成功 | +| message | string | 返回消息 | + +返回值 + +```json +{ + "status": 0, + "message": "success" +} +``` + +------ + +#### 流水线阶段步骤删除 + +``` +DELETE /api/ci/pipelines/{id}/{stage_id}/{step_id}/delete_step +``` + +*示例* + +```bash +curl -X DELETE \ +https://localhost:3000/api/ci/pipelines/1/6/2/delete_stage.json | jq +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| -------- | ---- | ---- | -------- | +| id | 是 | int | 流水线id | +| stage_id | 是 | int | 阶段id | +| step_id | 是 | int | 步骤id | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------- | ------ | ------------ | +| status | int | 状态码 0成功 | +| message | string | 返回消息 | + +返回值 + +```json +{ + "status": 0, + "message": "success" +} +``` + +------ + +#### 阶段模板查询 + +``` +GET /api/ci/templates/templates_by_stage?stage_type={stage_type} +``` + +*示例* + +```bash +curl -X GET \ +http://localhost:3000/api/ci/templates/templates_by_stage.json?stage_type=build | jq +``` + +*请求参数说明:* + +| 参数名 | 必选 | 类型 | 说明 | +| ---------- | ---- | ------ | --------------------------------------------- | +| stage_type | 是 | string | 阶段类型:init/build/deploy/customize/confirm | + +*返回参数说明:* + +| 参数名 | 类型 | 说明 | +| ------------- | ------ | ---------------- | +| category | string | 分类名称 | +| templates | arr | 分类下的模板列表 | +| id | int | 模板id | +| template_name | string | 模板名称 | +| content | String | 模板内容 | + +返回值 + +```json +[ + { + "category": "java", + "templates": [ + { + "id": 3, + "template_name": "maven", + "stage_type": "build", + "category": "java", + "content": "#maven", + "created_at": "2021-01-11T17:28:34.000+08:00", + "updated_at": "2021-01-11T17:28:36.000+08:00" + }, + { + "id": 4, + "template_name": "gradle", + "stage_type": "build", + "category": "java", + "content": "#gradle", + "created_at": "2021-01-11T17:28:34.000+08:00", + "updated_at": "2021-01-11T17:28:36.000+08:00" + } + ] + }, + { + "category": "c++", + "templates": [ + { + "id": 5, + "template_name": "make", + "stage_type": "build", + "category": "c++", + "content": "#make", + "created_at": "2021-01-11T17:29:17.000+08:00", + "updated_at": "2021-01-11T17:29:18.000+08:00" + } + ] + } +] +``` + +------ + + +#### 解除CI服务器绑定 ``` DELETE /api/users/ci/cloud_account/unbind ``` diff --git a/app/controllers/ci/pipelines_controller.rb b/app/controllers/ci/pipelines_controller.rb new file mode 100644 index 000000000..0ac53d80a --- /dev/null +++ b/app/controllers/ci/pipelines_controller.rb @@ -0,0 +1,175 @@ +class Ci::PipelinesController < ApplicationController + + # ======流水线相关接口========== # + def list + @pipelines = Ci::Pipeline.all + end + + def create + ActiveRecord::Base.transaction do + pipeline = Ci::Pipeline.new(pipeline_name: params[:pipeline_name], file_name: params[:file_name]) + pipeline.save! + + # 默认创建四个初始阶段 + init_stages = Ci::PipelineStage::INIT_STAGES + index = 0 + init_stages.each do |type, name| + pipeline.pipeline_stages.build( + stage_name: name, + stage_type: type, + show_index: index + ).save! + index += 1 + end + render_ok + end + rescue Exception => ex + render_error(ex.message) + end + + def update + pipeline = Ci::Pipeline.find(params[:id]) + if pipeline + pipeline.update!(pipeline_name: params[:pipeline_name]) + end + render_ok + rescue Exception => ex + render_error(ex.message) + end + + def destroy + pipeline = Ci::Pipeline.find(params[:id]) + if pipeline + pipeline.destroy! + end + render_ok + rescue Exception => ex + render_error(ex.message) + end + + def content + @yaml = "#pipeline \n" + stages = Ci::Pipeline.find(params[:id]).pipeline_stages + if stages && !stages.empty? + init_step = stages.first.pipeline_stage_steps.first + @yaml += init_step.content + "\n" + "steps:\n" + stages = stages.slice(1, stages.size - 1) + unless stages.empty? + stages.each do |stage| + steps = stage.pipeline_stage_steps + next unless steps && !steps.empty? + steps.each do |step| + @yaml += step.content + "\n" + end + end + end + end + end + + # =========阶段相关接口========= # + def stages + pipeline_id = params[:id] + @pipeline_stages = Ci::PipelineStage.where('pipeline_id=?', pipeline_id).order('show_index asc') + end + + def create_stage + ActiveRecord::Base.transaction do + stages = params[:stages] + unless stages.empty? + stages.each do |stage| + pipeline_stage = Ci::PipelineStage.new(stage_name: stage[:stage_name], + stage_type: stage[:stage_type].blank? ? 'customize' : stage[:stage_type], + pipeline_id: params[:id], show_index: stage[:show_index]) + pipeline_stage.save! + end + end + render_ok + end + rescue Exception => ex + render_error(ex.message) + end + + def update_stage + pipeline_stage = Ci::PipelineStage.find(params[:stage_id]) + if pipeline_stage + pipeline_stage.update!(stage_name: params[:stage_name], show_index: params[:show_index]) + end + render_ok + rescue Exception => ex + render_error(ex.message) + end + + def delete_stage + pipeline_stage = Ci::PipelineStage.find(params[:stage_id]) + if pipeline_stage + pipeline_stage.destroy! + end + render_ok + rescue Exception => ex + render_error(ex.message) + end + + def sort_stage + stages = params[:stage_index] + if stages && !stages.empty? + stages.each do |stage| + pipeline_stage = Ci::PipelineStage.find(stage[:id]) + if pipeline_stage + pipeline_stage.update!(show_index: stage[:show_index]) + end + end + end + render_ok + rescue Exception => ex + render_error(ex.message) + end + + # ========步骤相关接口========= # + def steps + @pipeline_stage_steps = Ci::PipelineStageStep.where('stage_id=?', params[:stage_id]).order('show_index asc') + end + + def create_stage_step + ActiveRecord::Base.transaction do + steps = params[:steps] + unless steps.empty? + steps.each do |step| + step = Ci::PipelineStageStep.new(step_name: step[:step_name], stage_id: params[:stage_id], + template_id: step[:template_id], content: step[:content], show_index: step[:show_index]) + step.save! + end + end + render_ok + end + rescue Exception => ex + render_error(ex.message) + end + + def update_stage_step + ActiveRecord::Base.transaction do + steps = params[:steps] + unless steps.empty? + steps.each do |step| + pipeline_stage_step = Ci::PipelineStageStep.find(step[:id]) + if pipeline_stage_step + pipeline_stage_step.update(step_name: step[:step_name], content: step[:content], + show_index: step[:show_index], template_id: step[:template_id]) + end + end + end + render_ok + end + rescue Exception => ex + render_error(ex.message) + end + + def delete_stage_step + pipeline_stage_step = Ci::PipelineStageStep.find(params[:step_id]) + if pipeline_stage_step + pipeline_stage_step.destroy! + end + render_ok + rescue Exception => ex + render_error(ex.message) + end +end diff --git a/app/controllers/ci/templates_controller.rb b/app/controllers/ci/templates_controller.rb new file mode 100644 index 000000000..4423bb402 --- /dev/null +++ b/app/controllers/ci/templates_controller.rb @@ -0,0 +1,26 @@ +class Ci::TemplatesController < ApplicationController + + def list + @templates = Ci::Template.all + end + + def templates_by_stage + stage_type = params[:stage_type] + @templates = Ci::Template.where("stage_type = ?", stage_type) + #根据模板类别分组 + @category_templates = @templates.group_by{ |template| template.category } + end + + def create + template = Ci::Template.new(template_name: params[:template_name], + stage_type: params[:stage_type], + category: params[:category], + content: params[:content] + ) + template.save! + render_ok + rescue Exception => ex + render_error(ex.message) + end + +end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb new file mode 100644 index 000000000..f69b7e46d --- /dev/null +++ b/app/models/ci/pipeline.rb @@ -0,0 +1,19 @@ +# == Schema Information +# +# Table name: ci_pipelines +# +# id :integer not null, primary key +# pipeline_name :string(255) not null +# pipeline_status :integer default("0"), not null +# file_name :string(255) not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class Ci::Pipeline < Ci::LocalBase + validates :pipeline_name, presence: {message: "流水线名称不能为空"} + validates :file_name, presence: {message: "流水线文件名称不能为空"} + + has_many :pipeline_stages, -> { reorder(show_index: :asc) }, foreign_key: "pipeline_id", :class_name => 'Ci::PipelineStage', dependent: :destroy + +end diff --git a/app/models/ci/pipeline_stage.rb b/app/models/ci/pipeline_stage.rb new file mode 100644 index 000000000..3cf23ad99 --- /dev/null +++ b/app/models/ci/pipeline_stage.rb @@ -0,0 +1,24 @@ +# == Schema Information +# +# Table name: ci_pipeline_stages +# +# id :integer not null, primary key +# stage_name :string(255) not null +# stage_type :string(255) not null +# pipeline_id :integer not null +# show_index :integer default("0"), not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class Ci::PipelineStage < Ci::LocalBase + + validates :stage_name, presence: {message: "阶段名称不能为空"} + validates :stage_type, presence: {message: "阶段类型不能为空"} + + belongs_to :pipeline, foreign_key: :pipeline_id, :class_name => 'Ci::Pipeline' + has_many :pipeline_stage_steps, -> { reorder(show_index: :asc) }, foreign_key: "stage_id", :class_name => 'Ci::PipelineStageStep', dependent: :destroy + + INIT_STAGES = {init:"初始化", build:"编译构建", deploy:"部署", confirm:"确认"}.freeze + +end diff --git a/app/models/ci/pipeline_stage_step.rb b/app/models/ci/pipeline_stage_step.rb new file mode 100644 index 000000000..2d7c8721b --- /dev/null +++ b/app/models/ci/pipeline_stage_step.rb @@ -0,0 +1,22 @@ +# == Schema Information +# +# Table name: ci_pipeline_stage_steps +# +# id :integer not null, primary key +# step_name :string(255) not null +# stage_id :integer not null +# template_id :integer +# content :text(65535) +# show_index :integer +# created_at :datetime not null +# updated_at :datetime not null +# + +class Ci::PipelineStageStep < Ci::LocalBase + + validates :step_name, presence: {message: "步骤名称不能为空"} + validates :stage_id, presence: {message: "阶段id不能为空"} + + belongs_to :pipeline_stage, foreign_key: :stage_id, :class_name => 'Ci::PipelineStage' + has_one :template, :class_name => 'Ci::Template', foreign_key: :template_id +end diff --git a/app/models/ci/template.rb b/app/models/ci/template.rb new file mode 100644 index 000000000..34aab41df --- /dev/null +++ b/app/models/ci/template.rb @@ -0,0 +1,22 @@ +# == Schema Information +# +# Table name: ci_templates +# +# id :integer not null, primary key +# template_name :string(255) not null +# stage_type :string(255) not null +# category :string(255) not null +# content :text(65535) not null +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_ci_templates_on_stage_type (stage_type) +# + +class Ci::Template < Ci::LocalBase + validates :template_name, presence: {message: "模板名称不能为空"} + validates :stage_type, presence: {message: "阶段类型不能为空"} + validates :category, presence: {message: "模板类型不能为空"} +end diff --git a/app/views/ci/pipeline_stage_steps/_list.json.jbuilder b/app/views/ci/pipeline_stage_steps/_list.json.jbuilder new file mode 100644 index 000000000..a3d592fbd --- /dev/null +++ b/app/views/ci/pipeline_stage_steps/_list.json.jbuilder @@ -0,0 +1,9 @@ +json.id pipeline_stage_step.id +json.step_name pipeline_stage_step.step_name +json.stage_id pipeline_stage_step.stage_id +json.template_id pipeline_stage_step.template_id +json.show_index pipeline_stage_step.show_index +json.content pipeline_stage_step.content +json.created_at pipeline_stage_step.created_at +json.updated_at pipeline_stage_step.updated_at + diff --git a/app/views/ci/pipeline_stages/_list.json.jbuilder b/app/views/ci/pipeline_stages/_list.json.jbuilder new file mode 100644 index 000000000..1e782ee40 --- /dev/null +++ b/app/views/ci/pipeline_stages/_list.json.jbuilder @@ -0,0 +1,8 @@ +json.id pipeline_stage.id +json.stage_name pipeline_stage.stage_name +json.stage_type pipeline_stage.stage_type +json.pipeline_id pipeline_stage.pipeline_id +json.show_index pipeline_stage.show_index +json.created_at pipeline_stage.created_at +json.updated_at pipeline_stage.updated_at + diff --git a/app/views/ci/pipelines/_list.json.jbuilder b/app/views/ci/pipelines/_list.json.jbuilder new file mode 100644 index 000000000..aab9ce142 --- /dev/null +++ b/app/views/ci/pipelines/_list.json.jbuilder @@ -0,0 +1,9 @@ +json.id pipeline.id +json.pipeline_name pipeline.pipeline_name +json.pipeline_status pipeline.pipeline_status +json.file_name pipeline.file_name +json.created_at pipeline.created_at +json.updated_at pipeline.updated_at +json.stages pipeline.pipeline_stages do |pipeline_stage| + json.partial! "/ci/pipeline_stages/list", pipeline_stage: pipeline_stage +end diff --git a/app/views/ci/pipelines/content.json.jbuilder b/app/views/ci/pipelines/content.json.jbuilder new file mode 100644 index 000000000..f7237bd33 --- /dev/null +++ b/app/views/ci/pipelines/content.json.jbuilder @@ -0,0 +1 @@ +json.content @yaml \ No newline at end of file diff --git a/app/views/ci/pipelines/list.json.jbuilder b/app/views/ci/pipelines/list.json.jbuilder new file mode 100644 index 000000000..7cfbeb1a6 --- /dev/null +++ b/app/views/ci/pipelines/list.json.jbuilder @@ -0,0 +1,3 @@ +json.pipelines @pipelines do |pipeline| + json.partial! "/ci/pipelines/list", pipeline: pipeline +end \ No newline at end of file diff --git a/app/views/ci/pipelines/stages.json.jbuilder b/app/views/ci/pipelines/stages.json.jbuilder new file mode 100644 index 000000000..c7a65ecfe --- /dev/null +++ b/app/views/ci/pipelines/stages.json.jbuilder @@ -0,0 +1,3 @@ +json.stages @pipeline_stages do |pipeline_stage| + json.partial! "/ci/pipeline_stages/list", pipeline_stage: pipeline_stage +end \ No newline at end of file diff --git a/app/views/ci/pipelines/steps.json.jbuilder b/app/views/ci/pipelines/steps.json.jbuilder new file mode 100644 index 000000000..31e8ca6ac --- /dev/null +++ b/app/views/ci/pipelines/steps.json.jbuilder @@ -0,0 +1,3 @@ +json.steps @pipeline_stage_steps do |pipeline_stage_step| + json.partial! "/ci/pipeline_stage_steps/list", pipeline_stage_step: pipeline_stage_step +end \ No newline at end of file diff --git a/app/views/ci/templates/_list.json.jbuilder b/app/views/ci/templates/_list.json.jbuilder new file mode 100644 index 000000000..1aff25a43 --- /dev/null +++ b/app/views/ci/templates/_list.json.jbuilder @@ -0,0 +1,8 @@ +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.created_at template.created_at +json.updated_at template.updated_at + diff --git a/app/views/ci/templates/_templates_by_stage.json.jbuilder b/app/views/ci/templates/_templates_by_stage.json.jbuilder new file mode 100644 index 000000000..141e8d5bd --- /dev/null +++ b/app/views/ci/templates/_templates_by_stage.json.jbuilder @@ -0,0 +1,4 @@ +json.category category +json.templates templates do |template| + json.partial! "/ci/templates/list", template: template +end \ No newline at end of file diff --git a/app/views/ci/templates/list.json.jbuilder b/app/views/ci/templates/list.json.jbuilder new file mode 100644 index 000000000..3b463057b --- /dev/null +++ b/app/views/ci/templates/list.json.jbuilder @@ -0,0 +1,3 @@ +json.templates @templates do |template| + json.partial! "/ci/templates/list", template: template +end \ No newline at end of file diff --git a/app/views/ci/templates/templates_by_stage.json.jbuilder b/app/views/ci/templates/templates_by_stage.json.jbuilder new file mode 100644 index 000000000..898207941 --- /dev/null +++ b/app/views/ci/templates/templates_by_stage.json.jbuilder @@ -0,0 +1,3 @@ +json.array! @category_templates do |category, templates| + json.partial! "/ci/templates/templates_by_stage", category: category, templates: templates +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index c6282581b..f72d0ead3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,6 +31,31 @@ Rails.application.routes.draw do end end + resources :templates, only: [:list,:templates_by_stage,:create] do + collection do + get :list + get :templates_by_stage + end + end + + resources :pipelines do + collection do + get :list + end + member do + get :content + get :stages + post :create_stage + put :sort_stage + delete :delete_stage, :path => ":stage_id/delete_stage", to: 'pipelines#delete_stage' + put :update_stage, :path => ":stage_id/update_stage", to: 'pipelines#update_stage' + get :stage_steps, :path => ":stage_id/steps", to: 'pipelines#steps' + post :create_stage_step, :path => ":stage_id/create_step", to: 'pipelines#create_stage_step' + delete :delete_stage_step, :path => ":stage_id/:step_id/delete_step", to: 'pipelines#delete_stage_step' + put :update_stage_step, :path => ":stage_id/update_step", to: 'pipelines#update_stage_step' + end + end + # resources :repos, only: :index do # collection do # get 'get_trustie_pipeline', to: 'builds#get_trustie_pipeline', as: 'get_trustie_pipeline' diff --git a/db/migrate/20210108015318_create_ci_templates.rb b/db/migrate/20210108015318_create_ci_templates.rb new file mode 100644 index 000000000..80594513b --- /dev/null +++ b/db/migrate/20210108015318_create_ci_templates.rb @@ -0,0 +1,14 @@ +class CreateCiTemplates < ActiveRecord::Migration[5.2] + def change + create_table :ci_templates do |t| + t.string :template_name, null: false, comment: '模板名称' + t.string :stage_type, null: false, comment: '模板所属阶段类型:init/build/deploy/customize/confirm' + t.string :category, null: false, comment: '模板分类' + t.text :content, null: false, comment: '模板yml内容' + + t.timestamps + end + add_index :ci_templates, [:stage_type] + end +end + diff --git a/db/migrate/20210108055023_create_ci_pipelines.rb b/db/migrate/20210108055023_create_ci_pipelines.rb new file mode 100644 index 000000000..d14278208 --- /dev/null +++ b/db/migrate/20210108055023_create_ci_pipelines.rb @@ -0,0 +1,11 @@ +class CreateCiPipelines < ActiveRecord::Migration[5.2] + def change + create_table :ci_pipelines do |t| + t.string :pipeline_name, null: false, comment: '流水线名称' + t.string :pipeline_status, null: false, comment: 'successed/failed/running/errored/pending/killed/unknown' , default: 'unknown' + t.string :file_name, null: false, comment: '文件名称' + + t.timestamps + end + end +end diff --git a/db/migrate/20210108062016_create_ci_pipeline_stages.rb b/db/migrate/20210108062016_create_ci_pipeline_stages.rb new file mode 100644 index 000000000..8f7365a8e --- /dev/null +++ b/db/migrate/20210108062016_create_ci_pipeline_stages.rb @@ -0,0 +1,12 @@ +class CreateCiPipelineStages < ActiveRecord::Migration[5.2] + def change + create_table :ci_pipeline_stages do |t| + t.string :stage_name, null: false, comment: '阶段名称' + t.string :stage_type, null: false, comment: '阶段类型:init/build/deploy/customize/confirm' + t.integer :pipeline_id, null: false, comment: '阶段所属流水线id' + t.integer :show_index, null: false, comment: '阶段排序', default: 0 + + t.timestamps + end + end +end diff --git a/db/migrate/20210111013512_create_ci_pipeline_stage_steps.rb b/db/migrate/20210111013512_create_ci_pipeline_stage_steps.rb new file mode 100644 index 000000000..a4e38e132 --- /dev/null +++ b/db/migrate/20210111013512_create_ci_pipeline_stage_steps.rb @@ -0,0 +1,13 @@ +class CreateCiPipelineStageSteps < ActiveRecord::Migration[5.2] + def change + create_table :ci_pipeline_stage_steps do |t| + t.string :step_name, null: false, comment: '步骤名称' + t.integer :stage_id, null: false, comment: '阶段id' + t.integer :template_id, comment: '模板id' + t.text :content + t.integer :show_index, null: false, comment: '阶段排序', default: 0 + + t.timestamps + end + end +end