diff --git a/.gitignore b/.gitignore index 164dc649..836852ea 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,7 @@ vendor/bundle/ /Users /files /public/images/avatars +/public/cache_repository /public/files /workspace /log diff --git a/.trustie-pipeline.yml b/.trustie-pipeline.yml new file mode 100644 index 00000000..8f326548 --- /dev/null +++ b/.trustie-pipeline.yml @@ -0,0 +1,22 @@ +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: install + image: ruby:2.4.5 + commands: + - gem install bundler + - bundle -v + - bundle install --jobs=1 --retry=1 + +- name: test + image: ruby:2.4.5 + volumes: + - name: bundle + path: /usr/local/bundle + commands: + - rake diff --git a/Gemfile b/Gemfile index baca7990..8aff5eef 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,6 @@ source 'https://gems.ruby-china.com' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.3.7' - gem 'rails', '~> 5.2.0' gem 'mysql2', '>= 0.4.4', '< 0.6.0' gem 'puma', '~> 3.11' @@ -19,8 +17,6 @@ gem 'kaminari', '~> 1.1', '>= 1.1.1' gem 'bootsnap', '>= 1.1.0', require: false -gem 'gitlab', path: 'lib/gitlab-cli' - gem 'chinese_pinyin' gem 'rack-cors' @@ -74,6 +70,7 @@ group :development do gem 'listen', '>= 3.0.5', '< 3.2' gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' + gem "annotate", "~> 2.6.0" end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 427045ac..aeaf07bb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,10 +1,3 @@ -PATH - remote: lib/gitlab-cli - specs: - gitlab (3.2.0) - httparty - terminal-table - GEM remote: https://gems.ruby-china.com/ specs: @@ -61,6 +54,9 @@ GEM public_suffix (>= 2.0.2, < 5.0) ancestry (3.0.7) activerecord (>= 3.2.0) + annotate (2.6.5) + activerecord (>= 2.3.0) + rake (>= 0.8.7) archive-zip (0.12.0) io-like (~> 0.3.0) arel (9.0.0) @@ -139,9 +135,6 @@ GEM harmonious_dictionary (0.0.1) hashie (3.6.0) htmlentities (4.3.4) - httparty (0.18.0) - mime-types (~> 3.0) - multi_xml (>= 0.5.2) i18n (1.8.2) concurrent-ruby (~> 1.0) io-like (0.3.1) @@ -178,9 +171,6 @@ GEM mimemagic (~> 0.3.2) maruku (0.7.3) method_source (0.9.2) - mime-types (3.3.1) - mime-types-data (~> 3.2015) - mime-types-data (3.2019.1009) mimemagic (0.3.4) mini_mime (1.0.2) mini_portile2 (2.4.0) @@ -405,8 +395,6 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) thor (1.0.1) thread_safe (0.3.6) tilt (2.0.10) @@ -442,6 +430,7 @@ DEPENDENCIES acts-as-taggable-on (~> 6.0) acts_as_list ancestry + annotate (~> 2.6.0) awesome_print axlsx (~> 3.0.0.pre) axlsx_rails (~> 0.5.2) @@ -457,7 +446,6 @@ DEPENDENCIES enumerize faraday (~> 0.15.4) font-awesome-sass (= 4.7.0) - gitlab! grape-entity (~> 0.7.1) groupdate (~> 4.1.0) harmonious_dictionary (~> 0.0.1) @@ -509,8 +497,5 @@ DEPENDENCIES whenever wkhtmltopdf-binary -RUBY VERSION - ruby 2.3.7p456 - BUNDLED WITH 2.1.4 diff --git a/README.md b/README.md index 61f68b32..10600ca6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,15 @@ +Trustie (确实)是一个以大众化协同开发、开放式资源共享、持续性可信评估为核心机理,面向高校创新实践的在线协作平台。 + +## 特性 + +- 软件创作与生产深度融合的软件开发环境体系结构 软件自由创作和工程生产的高效衔接,适于软件开发中群体智慧的有效汇聚。 + +- 构件化协同开发环境的可扩展运行框架多样化工具的集成和联动,形成了强动态扩展能力的平台框架。 + +- “互联网即资源库”的全新软件复用模式 成长式软件资源管理系统,实现了分散资源的知识融合、资源的可持续增长和有效复用。 + +## 部署 -# 本地开发部署步骤 ### 1. 安装依赖包 @@ -79,4875 +89,24 @@ http://localhost:3000/ ``` ---- +## 页面展示 +- 代码库 -# API文档 +![](docs/figs/code.png) -## 基本介绍 -### 开发API服务地址: +- 任务管理 +![](docs/figs/issue_manage.png) -**https://testgitea.trustie.net/** +- 任务查看 +![](docs/figs/issue_view.png) -响应状态说明: +- 任务指派 -|字段|类型|说明| -|-|-|-| -|status |int |响应状态码,0:请求成功,-1: 请求失败| -|message |string |响应说明 | +![](docs/figs/issue_assign2.png) +- 里程碑 -### API接口 ---- - -#### 用户注册(通过其他平台) -``` -POST accounts/remote_register -``` -*示例* -``` -curl -X POST \ --d "email=2456233122@qq.com" \ --d "password=djs_D_00001" \ --d "username=16895620" \ --d "platform=forge" \ -http://localhost:3000/api/accounts/remote_register | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|email |是|string |邮箱 | -|username |是|string |登录名 | -|password |是|string |秘密 | -|platform |否|string |用户来源的相关平台,取值范围['educoder', 'trustie', 'forge'], 默认值为forge | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|user|json object |返回数据| -|-- id |int |用户id | -|-- token |string|用户token| - - -返回值 -``` -{ - "status": 0, - "message": "success", - "user": { - "id": 36400, - "token": "8c87a80d9cfacc92fcb2451845104f35119eda96" - } -} -``` ---- - -#### 获取当前登录用户信息 -``` -GET api/users/me -``` -*示例* -``` -curl -X GET http://localhost:3000/api/users/me | jq -``` - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|user_id |int |用户id | -|username |string|用户名称| -|admin |boolean|是否为管理用户| -|login |string|登录名| -|image_url |string|用户头像| - - -返回值 -``` -{ - "username": "18816895620", - "login": "18816895620", - "user_id": 36401, - "image_url": "avatars/User/b", - "admin": false -} -``` ---- - -#### 用户列表(带搜索功能) -``` -GET api/users/list -``` -*示例* -``` -curl -X GET \ --d "limit=10" \ --d "search=18816895620" -http://localhost:3000/api/users/list | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|page |否|int |页数,第几页 | -|limit |否|int |每页多少条数据,默认15条 | -|search |否|string |用户名、登录名匹配搜索 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|total_count |int |总用户条数 | -|users |array| | -|-- username |string|用户全名| -|-- login |string|用户登录名| -|-- user_id |int|用户id| -|-- image_url |string|用户头像| - -返回值 -``` -{ - "total_count": 1, - "users": [ - { - "username": "18816895620", - "login": "18816895620", - "user_id": 36401, - "image_url": "avatars/User/b" - } - ] -} -``` ---- - -#### 获取项目类别列表(可根据名称搜素) -``` -GET api/project_categories -``` -*示例* -``` -curl -X GET \ --d "name=大数据" \ -http://localhost:3000/api/project_categories/ | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|name |否|string |类别名称 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|project_categories|array |返回数据| -|-- id |int |类别id | -|-- name |string|类别名称| - - -返回值 -``` -{ - "project_categories": [ - { - "id": 1, - "name": "大数据" - } - ] -} -``` ---- - -#### 获取项目语言列表(可根据名称搜素) -``` -GET api/project_languages -``` -*示例* -``` -curl -X GET \ --d "name=Ruby" \ -http://localhost:3000/api/project_languages/ | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|name |否|string |类别名称 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|project_languages|array |返回数据| -|-- id |int |语言id | -|-- name |string|语言名称| - - -返回值 -``` -{ - "project_languages": [ - { - "id": 1, - "name": "Ruby" - } - ] -} -``` ---- - -#### 获取.gitignore模板列表(可根据名称搜素) -``` -GET api/ignores -``` -*示例* -``` -curl -X GET \ --d "name=Ada" \ -http://localhost:3000/api/ignores/ | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|name |否|string |gitignore名称 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|ignores|array |返回数据| -|-- id |int |id | -|-- name |string|gitignore名称| - - -返回值 -``` -{ - "ignores": [ - { - "id": 1, - "name": "Ada" - } - ] -} -``` ---- - -#### 获取开源许可证列表(可根据名称搜素) -``` -GET api/licenses -``` -*示例* -``` -curl -X GET \ --d "name=AFL" \ -http://localhost:3000/api/licenses/ | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|name |否|string |开源许可证名称 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|licenses|array |返回数据| -|-- id |int |id | -|-- name |string|开源许可证名称| - - -返回值 -``` -{ - "licenses": [ - { - "id": 57, - "name": "AFL-1.2" - }, - { - "id": 76, - "name": "AFL-3.0" - }, - { - "id": 214, - "name": "AFL-1.1" - }, - { - "id": 326, - "name": "AFL-2.1" - }, - { - "id": 350, - "name": "AFL-2.0" - } - ] -} -``` ---- - -#### 创建项目 -``` -POST api/projects -``` -*示例* -``` -curl -X POST \ --d "user_id=36401" \ --d "name=hnfl_demo" \ --d "description=my first project" \ --d "repository_name=hnfl_demo" \ --d "project_category_id=1" \ --d "project_language_id=2" \ --d "ignore_id=2" \ --d "license_id=1" \ -http://localhost:3000/api/projects/ | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|user_id |是|int |用户id或者组织id | -|name |是|string |项目名称 | -|description |是|string |项目描述 | -|repository_name |是|string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 | -|project_category_id|是|int |项目类别id | -|project_language_id|是|int |项目语言id | -|ignore_id |否|int |gitignore相关id | -|license_id |否|int |开源许可证id | -|private |否|boolean|项目是否私有, true:为私有,false: 公开,默认为公开 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|id |int |id | -|name |string|项目名称| - - -返回值 -``` -{ - "id": 3240, - "name": "好项目" -} -``` ---- - -#### 新建镜像项目 -``` -POST api/projects/migrate -``` -*示例* -``` -curl -X POST \ --d "user_id=36408" \ --d "clone_addr=https://gitea.com/mx8090alex/golden.git" \ --d "name=golden_mirror1" \ --d "description=golden_mirror" \ --d "repository_name=golden_mirror1" \ --d "project_category_id=1" \ --d "project_language_id=2" \ -http://localhost:3000/api/projects/migrate.json?debug=admin | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|user_id |是|int |用户id或者组织id | -|name |是|string |项目名称 | -|clone_addr |是|string |镜像项目clone地址 | -|description |否|string |项目描述 | -|repository_name |是|string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 | -|project_category_id|是|int |项目类别id | -|project_language_id|是|int |项目语言id | -|is_mirror |否|boolean|是否设置为镜像, true:是, false:否,默认为否 | -|auth_username |否|string|镜像源仓库的登录用户名 | -|auth_password |否|string|镜像源仓库的登录秘密 | -|private |否|boolean|项目是否私有, true:为私有,false: 非私有,默认为公开 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|id |int |id | -|name |string|项目名称| - - -返回值 -``` -{ - "id": 3263, - "name": "ni项目" -} -``` - ---- -#### 手动同步镜像 -``` -POST api/repositories/:id/sync_mirror -``` -*示例* -``` -curl -X POST http://localhost:3000/api/repositories/1244/sync_mirror | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |仓库id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int |状态码, 0:标识请求成功 | -|message |string|服务端返回的信息说明| - - -返回值 -``` -{ - "status": 0, - "message": "success" -} -``` - ---- - -#### 项目详情 -``` -GET api/projects/:id -``` -*示例* -``` -curl -X GET http://localhost:3000/api/projects/3263 | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|id |int |id | -|name |string|项目名称| -|identifier |string|项目标识| -|is_public |boolean|项目是否公开, true:公开,false:私有| -|description |string|项目简介| -|repo_id |int|仓库id| -|repo_identifier|string|仓库标识| - - -返回值 -``` -{ - "name": "ni项目", - "identifier": "mirror_demo", - "is_public": true, - "description": "my first project mirror_demo", - "repo_id": 75073, - "repo_identifier": "mirror_demo" -} -``` ---- - -#### 编辑仓库信息 -``` -GET /api/repositories/:id/edit.json -``` -*示例* -``` -curl -X GET http://localhost:3000/api/repositories/:id/edit.json | jq -``` - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|identifier |string |仓库标识 | -|project_id |int|项目id| -|project_name |string|项目名称| -|project_identifier |string|项目标识| -|project_description |string|项目简介| -|project_category_id |int|项目类别id| -|project_language_id |int|项目语言id| -|private |boolean|项目是否私有, true:为私有,false: 公开 | - - -返回值 -``` -{ - "identifier": "mirror_demo", - "project_id": 3263, - "project_name": "ni项目", - "project_identifier": "mirror_demo", - "project_description": "my first project mirror_demo", - "project_category_id": 1, - "project_language_id": 2, - "private": false -} -``` ---- - -#### 修改项目信息 -``` -PATCH api/projects/:id -``` -*示例* -``` -curl -X PATCH \ --d "name=hnfl_demo" \ --d "description=my first project" \ --d "project_category_id=1" \ --d "project_language_id=2" \ --d "private=true" \ -http://localhost:3000/api/projects/3263.json | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|name |否|string |项目名称 | -|description |否|string |项目描述 | -|project_category_id|否|int |项目类别id | -|project_language_id|否|int |项目语言id | -|private |否|boolean|项目是否私有, true:为私有,false: 公开,默认为公开 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|id |int|id | -|identifier |string|项目标识| -|name |string|项目名称| -|description |string|项目简介| -|project_category_id|int|项目类别id| -|project_language_id|int|项目语言id| -|private |否|boolean|项目是否私有, true:为私有,false: 公开,默认为公开 | - - -返回值 -``` -{ - "id": 3263, - "identifier": "mirror_demo", - "name": "hnfl_demo", - "description": "my first project", - "project_category_id": 1, - "project_language_id": 2, - "is_public": true -} -``` ---- - -#### 删除项目 -``` -DELETE api/projects/:id -``` -*示例* -``` -curl -X DELETE http://localhost:3000/api/projects/3263.json | jq -``` - -注:只有超级管理员和项目拥有者才能删除仓库 - -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int|返回状态, 0: 表示操作成功 | -|message |string|返回信息说明| - - -返回值 -``` -{ - "status": 0, - "message": "success" -} -``` ---- - -#### 项目添加成员 -``` -POST api/projects/:id/members -``` -*示例* -``` -curl -X POST \ --d "user_id=36406" \ -http://localhost:3000/api/projects/3297/members | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|user_id |是|int |用户id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int |0:添加成功, -1: 添加失败, 1: 表示已经是项目成员 | -|message |string|返回信息说明| - - -返回值 -``` -{ - "status": 0, - "message": "success" -} -``` ---- - -#### 项目删除成员 -``` -DELETE api/projects/:id/members/remove -``` -*示例* -``` -curl -X DELETE \ --d "user_id=36400" \ -http://localhost:3000/api/projects/3263/members/remove | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|user_id |是|int |用户id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int |0:移除成功, -1: 移除失败, 1: 表示还不是项目成员 | -|message |string|返回信息说明| - - -返回值 -``` -{ - "status": 0, - "message": "success" -} -``` ---- - -#### 更改项目成员角色/权限 -``` -PUT api/projects/:id/members/change_role -``` -*示例* -``` -curl -X PUT \ --d "user_id=36400" \ --d "role=Developer" \ -http://localhost:3000/api/projects/3263/members/change_role | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|user_id |是|int |用户id | -|role |是|string |取值范围:"Manager", "Developer", "Reporter";分别为项目管理人员(拥有所有操作权限)、项目开发人员(只拥有读写权限)、项目报告人员(只拥有读权限) | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int |0:角色更改成功, -1: 更改失败失败, 1: 表示还不是项目成员 | -|message |string|返回信息说明| - - -返回值 -``` -{ - "status": 0, - "message": "success" -} -``` ---- - - -#### 项目成员列表 -``` -GET api/projects/:id/members -``` -*示例* -``` -curl -X GET \ --d "page=1" \ --d "limit=5" \ -http://localhost:3000/api/projects/3263/members | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|page |否|string |页数,第几页 | -|limit |否|string |每页多少条数据,默认15条 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|total_count |int |返回记录总条数 | -|members |array|项目成员信息| -|-- id |int|用户id| -|-- name |string|用户名称| -|-- login |string|用户登录名/标识| -|-- image_url |string|用户头像| -|-- is_owner |boolean|是否是项目的拥有者,true:是, false:不是| -|-- role |string|该用户在项目中的角色, Manager: 管理员(拥有操作权限); Developer:开发人员(只拥有读写权限); Reporter:报告人员(只拥有读权限)| - - -返回值 -``` -{ - "total_count": 2, - "members": [ - { - "id": 36401, - "name": "18816895620", - "login": "18816895620", - "image_url": "avatars/User/b", - "is_owner": true, - "role": "Manager" - }, - { - "id": 36399, - "name": "18816365620", - "login": "18816365620", - "image_url": "avatars/User/b", - "is_owner": false, - "role": "Developer" - } - ] -} -``` ---- - -#### Fork项目 -``` -POST /api/projects/:project_id/forks -``` -*示例* -``` -curl -X POST http://localhost:3000/api/projects/3297/forks | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|project_id |是|int |项目id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|id |int |项目id | -|identifier |string|项目标识| - - -返回值 -``` -{ - "id": 3290, - "identifier": "newadm" -} -``` ---- - -#### 获取代码目录列表 -``` -POST /api/repositories/:id/entries.json -``` -*示例* -``` -curl -X GET \ --d "ref=develop" \ -http://localhost:3000//api/repositories/3687/entries.json | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|ref |否|string |分支名称、tag名称或是提交记录id,默认为master分支 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|last_commit |object | | -|-- commit |object | | -|id |int |id | -|name |string|文件夹或文件名称| -|path |string|文件夹或文件相对路径| -|type |string|文件类型, file:文件,dir:文件目录| -|size |int|文件夹或文件大小 单位B| -|content |string|文件内容,| -|target |string|标签| - -返回值 -``` -{ - "last_commit": { - "commit": { - "sha": "3f2de4f78d2d7050486535082cd11cdfc9f3679e", - "url": "http://localhost:3003//api/repositories/api-cloud-platform/commits/3f2de4f78d2d7050486535082cd11cdfc9f3679e", - "message": "update README.md.", - "author": { - "name": "Gitee", - "email": "noreply@gitee.com", - "date": "2020-03-02T20:23:18+08:00" - }, - "committer": { - "name": "Gitee", - "email": "noreply@gitee.com", - "date": "2020-03-02T20:23:18+08:00" - }, - "timestamp": 1583151798, - "time_from_now": "3个月前" - }, - "author": null, - "committer": null - }, - "entries": [ - { - "name": "ace-gate", - "path": "ace-gate", - "sha": "c83f85fc63b14edcd6fc502eee9996f5a9993eca", - "type": "dir", - "size": 0, - "content": null, - "target": null, - "commit": { - "message": "v2.9 升级alibaba组件release版本\n", - "sha": "6117eaab86f71115f42f2a46ff1683015cda798d", - "created_at": "1970-01-01 08:00", - "time_from_now": "51年前", - "created_at_unix": null - } - }, - { - "name": "ace-sidecar", - "path": "ace-sidecar", - "sha": "38e41d7810876b464f8f1adcbf998e1b04f710a7", - "type": "dir", - "size": 0, - "content": null, - "target": null, - "commit": { - "message": "[Feature] 升级spring 版本&consul注册中心\n", - "sha": "c0a5dde35cfc87f7dbaf676aac397b184ba0e55b", - "created_at": "1970-01-01 08:00", - "time_from_now": "51年前", - "created_at_unix": null - } - }, - ... - ] -} -``` ---- - -#### 获取子目录代码列表/编辑某个具体的文件 -``` -GET /api/repositories/:id/sub_entries -``` -*示例* -``` -curl -X GET \ --d "ref=master" \ --d "filepath=test1_create_file.rb" \ -http://localhost:3000/api/repositories/87/sub_entries.json | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|filepath |是|string |文件夹、文件的相对路径 | -|ref |否|string |分支名称、tag名称或是提交记录id,默认为master分支 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|id |int |id | -|name |string|文件夹或文件名称| -|path |string|文件夹或文件相对路径| -|type |string|文件类型, file:文件,dir:文件目录| -|size |int|文件夹或文件大小 单位KB| -|content |string|文件内容,| -|target |string|标签| -|url |string|文件访问链接,带分支| -|html_url |string|文件访问链接,未标识分支| -|git_url |string|文件夹或文件的git仓库访问链接| -|download_url |string|文件下载、文件内容访问链接| - -返回值 -``` -[ - { - "name": "build.rc", - "path": "lib/build.rc", - "type": "", - "size": 1268, - "content": null, - "target": null, - "url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/contents/lib/build.rc?ref=master", - "html_url": "http://localhost:3003/18816895620/mirror_demo/src/branch/master/lib/build.rc", - "git_url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/git/blobs/191fcf1a63b3777e2977fcede7dd5309efdd70fe", - "download_url": null - }, - { - "name": "cfg.rc", - "path": "lib/cfg.rc", - "type": "file", - "size": 107, - "content": null, - "target": null, - "url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/contents/lib/cfg.rc?ref=master", - "html_url": "http://localhost:3003/18816895620/mirror_demo/src/branch/master/lib/cfg.rc", - "git_url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/git/blobs/0b91ba0ed1c00e130c77bb9058af3787fea986a0", - "download_url": "http://localhost:3003/18816895620/mirror_demo/raw/branch/master/lib/cfg.rc" - }, - { - "name": "fn", - "path": "lib/fn", - "type": "dir", - "size": 0, - "content": null, - "target": null, - "url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/contents/lib/fn?ref=master", - "html_url": "http://localhost:3003/18816895620/mirror_demo/src/branch/master/lib/fn", - "git_url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/git/blobs/e33bd45949ef8f804471d0b6b2c59728eb445989", - "download_url": null - } -] -``` ---- - -#### 项目类别列表(用于项目列表左侧导航中的项目类别列表) -``` -GET api/project_categories/group_list -``` -*示例* -``` -curl -X GET http://localhost:3000/api/project_categories/group_list | jq -``` - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|id |int |项目分类id | -|name |string|项目分类名称| -|projects_count |int |项目数量| - - -返回值 -``` -[ - { - "id": 1, - "name": "大数据", - "projects_count": 30 - }, - { - "id": 2, - "name": "机器学习", - "projects_count": 1 - }, - { - "id": 3, - "name": "深度学习", - "projects_count": 1 - } -] -``` ---- - -#### 项目类型列表(用于项目列表左侧导航上方中的项目类型列表) -``` -GET api/projects/group_type_list -``` -*示例* -``` -curl -X GET http://localhost:3000/api/projects/group_type_list | jq -``` - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|project_type |string|项目类型 | -|name |string|项目类型名称| -|projects_count |int |项目数量| - - -返回值 -``` -[ - { - "project_type": "common", - "name": "开源托管项目", - "projects_count": 2106 - }, - { - "project_type": "mirror", - "name": "开源镜像项目", - "projects_count": 1 - } -] -``` ---- - -#### 项目列表 -``` -GET api/projects -``` -*示例* -``` -curl -X GET \ --d "page=1" \ --d "limit=5" \ -http://localhost:3000/api/projects | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|page |否|string |页数,第几页 | -|limit |否|string |每页多少条数据,默认15条 | -|sort_by |否|string |排序类型, 取值:updated_on \| created_on \| forked_count \| praises_count, updated_on: 更新时间排序,created_on: 创建时间排序,forked_count: fork数据排序,praises_count: 点赞数量排序,默认为updated_on更新时间排序 | -|sort_direction|否|string |排序方式,取值为: desc \| asc; desc: 降序排序, asc: 升序排序, 默认为:desc | -|search |否|string |按照项目名称搜索 | -|category_id |否|int |项目类别id | -|language_id |否|int |项目语言id | -|project_type |否|string |项目类型, 取值为:common \| mirror; common:开源托管项目, mirror:开源镜像项目 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|total_count |int |项目总条数 | -|id |string |项目id | -|name |string|项目名称| -|description |string|项目简介| -|visits |int|流量数| -|forked_count |int|被fork的数量| -|praises_count |int|star数量| -|is_public |boolean|是否公开, true:公开,false:未公开| -|mirror_url |string|镜像url| -|last_update_time|int|最后更新时间,为UNIX格式的时间戳| -|author |object|项目创建者| -|-- name |string|用户名,也是用户标识| -|category |object|项目类别| -|-- id |int|项目类型id| -|-- name |string|项目类型名称| -|language |object|项目语言| -|-- id |int|项目语言id| -|-- name |string|项目语言名称| - - -返回值 -``` -{ - "total_count": 3096, - "projects": [ - { - "id": 1, - "name": "hnfl_demo1", - "description": "my first project", - "visits": 0, - "praises_count": 0, - "forked_count": 0, - "is_public": true, - "mirror_url": null, - "last_update_time": 1577697461, - "author": { - "name": "18816895620", - "image_url": "avatars/User/b" - }, - "category": { - "id": 1, - "name": "大数据" - }, - "language": { - "id": 2, - "name": "C" - } - }, - { - "id": 2, - "name": "hnfl_demo", - "description": "my first project", - "visits": 0, - "praises_count": 0, - "forked_count": 0, - "is_public": true, - "mirror_url": null, - "last_update_time": 1577697403, - "author": { - "name": "18816895620", - "image_url": "avatars/User/b" - }, - "category": { - "id": 1, - "name": "大数据" - }, - "language": { - "id": 2, - "name": "C" - } - }, - { - "id": 3, - "name": "统计局", - "description": "my first project", - "visits": 0, - "praises_count": 0, - "forked_count": 0, - "is_public": true, - "mirror_url": null, - "last_update_time": 1577415173, - "author": { - "name": "18816895620", - "image_url": "avatars/User/b" - }, - "category": { - "id": 1, - "name": "大数据" - }, - "language": { - "id": 2, - "name": "C" - } - }, - { - "id": 5, - "name": "开源同名", - "description": "my first project", - "visits": 0, - "praises_count": 0, - "forked_count": 0, - "is_public": false, - "mirror_url": "https://gitea.com/CasperVector/slew.git", - "last_update_time": 1577346228, - "author": { - "name": "18816895620", - "image_url": "avatars/User/b" - }, - "category": { - "id": 1, - "name": "大数据" - }, - "language": { - "id": 2, - "name": "C" - } - }, - { - "id": 7, - "name": "开源支持", - "description": "my first project", - "visits": 0, - "praises_count": 0, - "forked_count": 0, - "is_public": true, - "mirror_url": null, - "last_update_time": 1577341572, - "author": { - "name": "18816895620", - "image_url": "avatars/User/b" - }, - "category": { - "id": 1, - "name": "大数据" - }, - "language": { - "id": 2, - "name": "C" - } - } - ] -} -``` ---- - -### 获取分支列表 -``` -GET /api/projects/:id/branches -``` -*示例* -``` -curl -X GET http://localhost:3000/api/projects/4797/branches | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|id |项目id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|name |string|分支名称| -|user_can_push |boolean|用户是否可push| -|user_can_merge |boolean|用户是否客merge| -|protected |boolean|是否为保护分支| -|http_url |boolean|http链接| -|zip_url |boolean|zip包下载链接| -|tar_url |boolean|tar.gz下载链接| -|last_commit |object|最后提交记录| -|-- id |string|提交记录id| -|-- message |string|提交的说明信息| -|-- timestamp |int|提交时间,为UNIX时间戳| -|-- time_from_now|string|转换后的时间| -|author |object|提交用户| -|-- login |string|用户名称| -|-- image_url |string|用户头像| - - -返回值 -``` -[ - { - "name": "develop", - "user_can_push": true, - "user_can_merge": true, - "protected": false, - "http_url": "http://localhost:3003/18816895620/mirror_demo.git", - "zip_url": "http://localhost:3003/18816895620/mirror_demo/develop.zip", - "tar_url": "http://localhost:3003/18816895620/mirror_demo/develop.tar.gz", - "last_commit": { - "id": "735674d6696bddbafa993db9c67b40c41246c77f", - "message": "FIX test branch content\n", - "timestamp": 1577694074, - "time_from_now": "1天前" - }, - "author": { - "login": "18816895620", - "image_url": "avatars/User/b" - } - }, - { - "name": "master", - "user_can_push": true, - "user_can_merge": true, - "protected": false, - "http_url": "http://localhost:3003/18816895620/mirror_demo.git", - "zip_url": "http://localhost:3003/18816895620/mirror_demo/master.zip", - "tar_url": "http://localhost:3003/18816895620/mirror_demo/master.tar.gz", - "last_commit": { - "id": "19ac3bc45f62cc87a94b8ecce61101d8fd2dafd2", - "message": "合并pull request测试\n\n该功能很不错,感谢你的建议\n", - "timestamp": 1577244567, - "time_from_now": "6天前" - }, - "author": { - "login": "18816895620", - "image_url": "avatars/User/b" - } - } -] -``` ---- - -### 获取代码库标签列表 -``` -GET /api/repositories/:id/tags -``` -*示例* -``` -curl -X GET \ --d "limit=20" \ --d "page=1" \ -http://localhost:3000/api/repositories/5836/tags.json | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |仓库id | -|page |否|string |页数,第几页 | -|limit |否|string |每页多少条数据,默认20条 | - - -*返回参数说明:* - -|参数名|类型|说明| --|-|- -|name |string|分支名称| -|user_can_push |boolean|用户是否可push| -|user_can_merge |boolean|用户是否客merge| -|protected |boolean|是否为保护分支| -|http_url |boolean|http链接| -|zip_url |boolean|zip包下载链接| -|tar_url |boolean|tar.gz下载链接| -|last_commit |object|最后提交记录| -|-- id |string|提交记录id| -|-- message |string|提交的说明信息| -|-- timestamp |int|提交时间,为UNIX时间戳| -|-- time_from_now|string|转换后的时间| -|author |object|提交用户| -|-- login |string|用户名称| -|-- image_url |string|用户头像| - - -返回值 -``` -[ - { - "name": "develop", - "user_can_push": true, - "user_can_merge": true, - "protected": false, - "http_url": "http://localhost:3003/18816895620/mirror_demo.git", - "zip_url": "http://localhost:3003/18816895620/mirror_demo/develop.zip", - "tar_url": "http://localhost:3003/18816895620/mirror_demo/develop.tar.gz", - "last_commit": { - "id": "735674d6696bddbafa993db9c67b40c41246c77f", - "message": "FIX test branch content\n", - "timestamp": 1577694074, - "time_from_now": "1天前" - }, - "author": { - "login": "18816895620", - "image_url": "avatars/User/b" - } - }, - { - "name": "master", - "user_can_push": true, - "user_can_merge": true, - "protected": false, - "http_url": "http://localhost:3003/18816895620/mirror_demo.git", - "zip_url": "http://localhost:3003/18816895620/mirror_demo/master.zip", - "tar_url": "http://localhost:3003/18816895620/mirror_demo/master.tar.gz", - "last_commit": { - "id": "19ac3bc45f62cc87a94b8ecce61101d8fd2dafd2", - "message": "合并pull request测试\n\n该功能很不错,感谢你的建议\n", - "timestamp": 1577244567, - "time_from_now": "6天前" - }, - "author": { - "login": "18816895620", - "image_url": "avatars/User/b" - } - } -] -``` ---- - -## 仓库详情 -``` -GET /api/repositories/:id -``` -*示例* -``` -curl -X GET \ -http://localhost:3000/api/repositories/23.json | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|string |项目id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|identifier |string|仓库标识| -|project_id |int|项目id| -|project_identifier|string|项目标识| -|praises_count |int|点赞数量| -|forked_count |int|fork数量| -|watchers_count |int|关注数量| -|branches_count |int|分支数量| -|commits_count |int|总提交记录数量| -|issues_count |int|总提交记录数量| -|pull_requests_count |int|总提交记录数量| -|praised |boolean|当前登录用户是否已点赞,true:已点赞,fasle:未点赞, 用户未登录状态为null| -|watched |boolean|当前登录用户是否已关注,true:已关注,fasle:未关注, 用户未登录状态为null| -|permission |string|当前登录用户对该仓库的操作权限, Manager:管理员,可以在线编辑文件、在线新建文件、可以设置仓库的基本信息; Developer:开发人员,可在线编辑文件、在线新建文件、不能设置仓库信息; Reporter: 报告人员,只能查看信息,不能设置仓库信息、不能在线编辑文件、不能在线新建文件;用户未登录时也会返回Reporter, 说明也只有读取文件的权限 | -|size |int|仓库文件大小,单位:KB| -|type |int|项目类型; 2: 表示是一个镜像(具备同步功能), 1: 普通镜像项目(不具同步功能), 0: 普通托管项目, 3: fork项目| -|mirror_status |int|该字段在type字段为2(一个镜像)时才会出现; 0: 表示同步镜像成功;1: 表示正在同步镜像;2: 同步失败| -|mirror_url |string|镜像地址, 只有通过镜像过来的项目才会有这个地址| -|ssh_url |string|仓库ssh地址| -|clone_url |string|仓库克隆地址| -|empty |boolean|仓库是否为空,true: 空仓库;false: 非空仓库| -|private |boolean|仓库是否私有,true: 私有仓库;fasle: 非私有的| -|default_branch |string|仓库默认分支| -|full_name |string|仓库全名(带用户名)| -|author |object|提交用户| -|-- login |string|用户login| -|-- name |string|用户姓名| -|-- image_url |string|用户头像| - - -返回值 -``` -{ - "identifier": "mirror_demo", - "project_id": 3263, - "project_identifier": "mirror_demo", - "praises_count": 1, - "forked_count": 0, - "watchers_count": 1, - "branches_count": 6, - "commits_count": 107, - "issues_count": 0, - "pull_requests_count": 0, - "permission": "Manager", - "mirror_url": "https://gitea.com/CasperVector/slew.git", - "watched": true, - "praised": true, - "size": 446, - "ssh_url": "jasder@localhost:18816895620/mirror_demo.git", - "clone_url": "http://localhost:3003/18816895620/mirror_demo.git", - "default_branch": "master", - "empty": false, - "full_name": "18816895620/mirror_demo", - "mirror": false, - "private": false, - "author": { - "login": "18816895620", - "name": "美女", - "image_url": "avatars/User/b" - } -} -``` ---- - -## 获取提交记录列表 -``` -GET /api/repositories/:id/commits -``` -*示例* -``` -curl -X GET \ --d "sha=develop" \ --d "page=1" \ -http://localhost:3000/api/repositories/89/commits.json | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|sha |否|string |分支名称、提交记录的sha标识,默认为master分支 | -|page |否|int |页数, 默认为1 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|total_count|int|总记录条数| -|commits |array|提交记录的数组| -|-- sha |string|提交记录sha标识| -|-- message |string|提交的备注说明| -|-- timestamp |int|提交UNIX时间戳| -|-- time_from_now|string|提交距离当前的时间| -|author |object|提交用户| -|-- login |string|用户名称| -|-- image_url |string|用户头像| - - -返回值 -``` -{ - "total_count": 63, - "commits": [ - { - "sha": "19ac3bc45f62cc87a94b8ecce61101d8fd2dafd2", - "message": "合并pull request测试", - "timestamp": 1577244567, - "time_from_now": "7天前", - "author": { - "name": "18816895620", - "image_url": "avatars/User/b" - } - }, - { - "sha": "2b33c5f55214db41879936312ee43611406c4dbd", - "message": "FIX .", - "timestamp": 1577244474, - "time_from_now": "7天前", - "author": { - "name": "18816895620", - "image_url": "avatars/User/b" - } - } - ] -} -``` ---- - -## 获取某个提交记录(包含diff) -``` -GET /api/repositories/:id/commits/:sha -``` -*示例* -``` -curl -X GET \ -http://localhost:3000/api/repositories/5845/commits/b0c4a4a1487d53acebf2addc544b29938cad12df.json | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |仓库repository的id | -|sha |否|string |git的ref或者是提交记录commit的sha标识 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|additions |int|该commit下所有文件增加的总行数| -|deletions |int|该commit下所有文件删除的总行数| -|sha |string|提交记录sha标识| -|url |string|该commit的api访问地址| -|commit |object| | -|-- author |object| commit的作者用户| -|---- login |string|提交commit的用户名称| -|---- email |string|提交commit的用户邮箱| -|---- date |string|提交commit的时间| -|-- committer |object|提交者用户信息| -|---- login |string|committer的用户名称| -|---- email |string|committer的用户邮箱| -|---- date |string|committer的时间| -|-- message |string|提交信息| -|-- tree |object| | -|---- sha |string| tree结构的sha标识| -|author |object|forge平台的提交用户信息| -|-- id |int|用户id| -|-- login |string|用户登录名| -|-- name |string|用户名称| -|-- image_url |string|用户头像| -|committer |object|forge平台的committer用户信息| -|-- id |int|用户id| -|-- login |string|用户登录名| -|-- name |string|用户名称| -|-- image_url |string|用户头像| -|parents |array|父节点| -|-- sha |int|commit父节点的sha标识| -|-- url |string|commit父节点api访问地址| -|author |object|提交用户| -|-- login |string|用户名称| -|-- image_url |string|用户头像| -|files |array|文件数组| -|-- Name |string|文件名称| -|-- OldName |string|旧文件名称| -|-- Addition |string|增加的行数| -|-- Deletion |string|删除的行数| -|-- Type |string|1: 表示是新增加的文件,2:表示是修改的文件, 3: 表示该文件已经被删除| -|-- IsCreated |boolean|是否为新添加的文件,true:是; false:否| -|-- IsDeleted |boolean|是否为删除的文件,true:是;false:否| -|-- IsRenamed |boolean|是否为重命名的文件,true:是,false:否| -|-- IsBin |boolean|是否为二进制文件,true:是,false:否| -|-- IsLFSFile |boolean|是否git lfs操作的大文件,true:是,false:否| -|-- IsSubmodule |boolean|收否为子模块,true:是;false:否| -|-- Sections |array| | -|---- Name |string|文件名称| -|------ Lines |array|行数| -|-------- LeftIdx |int|分列视图时用,左侧开始行号, 0:表示没有行号| -|-------- RightIdx |int|分列视图时用,右侧开始行号| -|-------- Type |int|1: 表示未做修改的源代码,2: 表示增加的代码,3: 表示删除的代码,4: 统计说明,如:@@ -0,0 +1,11 @@| -|-------- Content |string|一行的文件内容| -|-------- Comments |string|评论信息| -|-------- SectionInfo |string|用户头像| -|---------- Path |string|文件路径| -|---------- LastLeftIdx |string| | -|---------- LastRightIdx |string| | -|---------- LeftIdx |string| | -|---------- RightIdx |string| | -|---------- LeftHunkSize |string| | -|---------- RightHunkSize |string| | - - -返回值 -``` -{ - "additions": 243, - "deletions": 32, - "sha": "c6c17ad47d6dbe4369d559847197b37b4090a46e", - "url": "http://localhost:3000/api/repositories/5845/commits/c6c17ad47d6dbe4369d559847197b37b4090a46e.json", - "commit": { - "author": { - "name": "GitHub", - "email": "noreply@github.com", - "date": "2020-05-20T20:15:27+08:00" - }, - "committer": { - "name": "GitHub", - "email": "noreply@github.com", - "date": "2020-05-20T20:15:27+08:00" - } - }, - "author": null, - "committer": null, - "parents": [ - { - "sha": "c8b8cfd85e375ad376833d04b9ca499bf9da355b", - "url": "http://localhost:3003//api/repositories/intelligent-test-platform/commits/c8b8cfd85e375ad376833d04b9ca499bf9da355b" - }, - { - "sha": "b0c4a4a1487d53acebf2addc544b29938cad12df", - "url": "http://localhost:3003//api/repositories/intelligent-test-platform/commits/b0c4a4a1487d53acebf2addc544b29938cad12df" - } - ], - "files": [ - { - "Name": "Dockerfile", - "OldName": "Dockerfile", - "Index": 1, - "Addition": 11, - "Deletion": 0, - "Type": 1, - "IsCreated": true, - "IsDeleted": false, - "IsBin": false, - "IsLFSFile": false, - "IsRenamed": false, - "IsSubmodule": false, - "Sections": [ - { - "Name": "", - "Lines": [ - { - "LeftIdx": 0, - "RightIdx": 0, - "Type": 4, - "Content": "@@ -0,0 +1,11 @@", - "Comments": null, - "SectionInfo": { - "Path": "Dockerfile", - "LastLeftIdx": 0, - "LastRightIdx": 0, - "LeftIdx": 0, - "RightIdx": 1, - "LeftHunkSize": 0, - "RightHunkSize": 11 - } - }, - { - "LeftIdx": 0, - "RightIdx": 1, - "Type": 2, - "Content": "+FROM adoptopenjdk/maven-openjdk8:latest", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 2, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 3, - "Type": 2, - "Content": "+ADD ./target/markov-demo-0.0.1-SNAPSHOT.jar /usr/local/markov-demo-0.0.1-SNAPSHOT.jar", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 4, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 5, - "Type": 2, - "Content": "+# Add docker-compose-wait tool -------------------", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 6, - "Type": 2, - "Content": "+ENV WAIT_VERSION 2.7.2", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 7, - "Type": 2, - "Content": "+ADD https://github.com/ufoscout/docker-compose-wait/releases/download/$WAIT_VERSION/wait /wait", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 8, - "Type": 2, - "Content": "+RUN chmod +x /wait", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 9, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 10, - "Type": 2, - "Content": "+EXPOSE 8080", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 11, - "Type": 2, - "Content": "+ENTRYPOINT [ \"java\", \"-jar\", \"/usr/local/markov-demo-0.0.1-SNAPSHOT.jar\" ]", - "Comments": null, - "SectionInfo": null - } - ] - } - ], - "IsIncomplete": false - }, - { - "Name": "docker-compose.yml", - "OldName": "docker-compose.yml", - "Index": 2, - "Addition": 42, - "Deletion": 0, - "Type": 1, - "IsCreated": true, - "IsDeleted": false, - "IsBin": false, - "IsLFSFile": false, - "IsRenamed": false, - "IsSubmodule": false, - "Sections": [ - { - "Name": "", - "Lines": [ - { - "LeftIdx": 0, - "RightIdx": 0, - "Type": 4, - "Content": "@@ -0,0 +1,42 @@", - "Comments": null, - "SectionInfo": { - "Path": "docker-compose.yml", - "LastLeftIdx": 0, - "LastRightIdx": 0, - "LeftIdx": 0, - "RightIdx": 1, - "LeftHunkSize": 0, - "RightHunkSize": 42 - } - }, - { - "LeftIdx": 0, - "RightIdx": 1, - "Type": 2, - "Content": "+version: '3.6'", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 2, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 3, - "Type": 2, - "Content": "+services:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 4, - "Type": 2, - "Content": "+ web:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 5, - "Type": 2, - "Content": "+ build: .", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 6, - "Type": 2, - "Content": "+ command: sh -c \"/wait && java -jar /usr/local/markov-demo-0.0.1-SNAPSHOT.jar\"", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 7, - "Type": 2, - "Content": "+ environment:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 8, - "Type": 2, - "Content": "+ - WAIT_HOSTS=container-mysql:3306", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 9, - "Type": 2, - "Content": "+ - WAIT_HOSTS_TIMEOUT=300", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 10, - "Type": 2, - "Content": "+ - WAIT_SLEEP_INTERVAL=30", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 11, - "Type": 2, - "Content": "+ - WAIT_HOST_CONNECT_TIMEOUT=30", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 12, - "Type": 2, - "Content": "+ - spring.datasource.url=jdbc:mysql://container-mysql:3306/markov_demo?useUnicode=true&characterEncoding=utf-8", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 13, - "Type": 2, - "Content": "+ depends_on:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 14, - "Type": 2, - "Content": "+ - container-mysql", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 15, - "Type": 2, - "Content": "+ ports:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 16, - "Type": 2, - "Content": "+ - '8080:8080'", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 17, - "Type": 2, - "Content": "+ expose:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 18, - "Type": 2, - "Content": "+ - '8080'", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 19, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 20, - "Type": 2, - "Content": "+ container-mysql:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 21, - "Type": 2, - "Content": "+ image: mysql:5.7", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 22, - "Type": 2, - "Content": "+ restart: always", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 23, - "Type": 2, - "Content": "+ environment:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 24, - "Type": 2, - "Content": "+ MYSQL_DATABASE: 'markov_demo'", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 25, - "Type": 2, - "Content": "+ # So you don't have to use root, but you can if you like", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 26, - "Type": 2, - "Content": "+ MYSQL_USER: 'root'", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 27, - "Type": 2, - "Content": "+ # You can use whatever password you like", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 28, - "Type": 2, - "Content": "+ MYSQL_PASSWORD: '123'", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 29, - "Type": 2, - "Content": "+ # Password for root access", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 30, - "Type": 2, - "Content": "+ MYSQL_ROOT_PASSWORD: '123'", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 31, - "Type": 2, - "Content": "+ ports:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 32, - "Type": 2, - "Content": "+ # : < MySQL Port running inside container>", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 33, - "Type": 2, - "Content": "+ - '3306:3306'", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 34, - "Type": 2, - "Content": "+ expose:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 35, - "Type": 2, - "Content": "+ # Opens port 3306 on the container", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 36, - "Type": 2, - "Content": "+ - '3306'", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 37, - "Type": 2, - "Content": "+ # Where our data will be persisted", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 38, - "Type": 2, - "Content": "+ volumes:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 39, - "Type": 2, - "Content": "+ - my-db:/tmp/mysql", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 40, - "Type": 2, - "Content": "+# Names our volume", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 41, - "Type": 2, - "Content": "+volumes:", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 42, - "Type": 2, - "Content": "+ my-db: {}", - "Comments": null, - "SectionInfo": null - } - ] - } - ], - "IsIncomplete": false - }, - { - "Name": "pom.xml", - "OldName": "pom.xml", - "Index": 3, - "Addition": 5, - "Deletion": 0, - "Type": 2, - "IsCreated": false, - "IsDeleted": false, - "IsBin": false, - "IsLFSFile": false, - "IsRenamed": false, - "IsSubmodule": false, - "Sections": [ - { - "Name": "", - "Lines": [ - { - "LeftIdx": 0, - "RightIdx": 0, - "Type": 4, - "Content": "@@ -26,6 +26,11 @@", - "Comments": null, - "SectionInfo": { - "Path": "pom.xml", - "LastLeftIdx": 0, - "LastRightIdx": 0, - "LeftIdx": 26, - "RightIdx": 26, - "LeftHunkSize": 6, - "RightHunkSize": 11 - } - }, - { - "LeftIdx": 26, - "RightIdx": 26, - "Type": 1, - "Content": " \t\t\tmybatis-spring-boot-starter", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 27, - "RightIdx": 27, - "Type": 1, - "Content": " \t\t\t2.1.2", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 28, - "RightIdx": 28, - "Type": 1, - "Content": " \t\t", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 29, - "Type": 2, - "Content": "+\t\t", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 30, - "Type": 2, - "Content": "+\t\t\torg.flywaydb", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 31, - "Type": 2, - "Content": "+\t\t\tflyway-core", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 32, - "Type": 2, - "Content": "+\t\t\t6.4.2", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 33, - "Type": 2, - "Content": "+\t\t", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 29, - "RightIdx": 34, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 30, - "RightIdx": 35, - "Type": 1, - "Content": " \t\t", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 31, - "RightIdx": 36, - "Type": 1, - "Content": " \t\t\tmysql", - "Comments": null, - "SectionInfo": null - } - ] - }, - { - "Name": "", - "Lines": [ - { - "LeftIdx": 0, - "RightIdx": 0, - "Type": 4, - "Content": " ", - "Comments": null, - "SectionInfo": { - "Path": "pom.xml", - "LastLeftIdx": 31, - "LastRightIdx": 36, - "LeftIdx": 103, - "RightIdx": 108, - "LeftHunkSize": 0, - "RightHunkSize": 0 - } - } - ] - } - ], - "IsIncomplete": false - }, - { - "Name": "src/main/resources/application.properties", - "OldName": "src/main/resources/application.properties", - "Index": 4, - "Addition": 5, - "Deletion": 4, - "Type": 2, - "IsCreated": false, - "IsDeleted": false, - "IsBin": false, - "IsLFSFile": false, - "IsRenamed": false, - "IsSubmodule": false, - "Sections": [ - { - "Name": "", - "Lines": [ - { - "LeftIdx": 0, - "RightIdx": 0, - "Type": 4, - "Content": "@@ -1,10 +1,11 @@", - "Comments": null, - "SectionInfo": { - "Path": "src/main/resources/application.properties", - "LastLeftIdx": 0, - "LastRightIdx": 0, - "LeftIdx": 1, - "RightIdx": 1, - "LeftHunkSize": 10, - "RightHunkSize": 11 - } - }, - { - "LeftIdx": 1, - "RightIdx": 0, - "Type": 3, - "Content": "-", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 1, - "Type": 2, - "Content": "+# Database configuration", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 2, - "RightIdx": 2, - "Type": 1, - "Content": " spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 3, - "RightIdx": 3, - "Type": 1, - "Content": " spring.datasource.url = jdbc:mysql://127.0.0.1:3306/markov_demo?useUnicode=true&characterEncoding=utf-8", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 4, - "RightIdx": 4, - "Type": 1, - "Content": " spring.datasource.username = root", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 5, - "RightIdx": 5, - "Type": 1, - "Content": " spring.datasource.password = 123", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 6, - "RightIdx": 6, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 7, - "RightIdx": 0, - "Type": 3, - "Content": "-", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 8, - "RightIdx": 0, - "Type": 3, - "Content": "-", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 9, - "RightIdx": 0, - "Type": 3, - "Content": "-mybatis.mapper-locations= classpath:mapping/*Mapper.xml", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 7, - "Type": 2, - "Content": "+mybatis.mapper-locations=classpath:mapping/*Mapper.xml", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 10, - "RightIdx": 8, - "Type": 1, - "Content": " mybatis.type-aliases-package=com.alibaba.markovdemo.entity", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 9, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 10, - "Type": 2, - "Content": "+spring.flyway.default-schema=markov_demo", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 11, - "Type": 2, - "Content": "+spring.flyway.locations=classpath:db/migration", - "Comments": null, - "SectionInfo": null - } - ] - } - ], - "IsIncomplete": false - }, - { - "Name": "src/main/resources/db/migration/V1__init_ddl.sql", - "OldName": "src/main/resources/db/migration/V1__init_ddl.sql", - "Index": 5, - "Addition": 179, - "Deletion": 0, - "Type": 1, - "IsCreated": true, - "IsDeleted": false, - "IsBin": false, - "IsLFSFile": false, - "IsRenamed": false, - "IsSubmodule": false, - "Sections": [ - { - "Name": "", - "Lines": [ - { - "LeftIdx": 0, - "RightIdx": 0, - "Type": 4, - "Content": "@@ -0,0 +1,179 @@", - "Comments": null, - "SectionInfo": { - "Path": "src/main/resources/db/migration/V1__init_ddl.sql", - "LastLeftIdx": 0, - "LastRightIdx": 0, - "LeftIdx": 0, - "RightIdx": 1, - "LeftHunkSize": 0, - "RightHunkSize": 179 - } - }, - { - "LeftIdx": 0, - "RightIdx": 1, - "Type": 2, - "Content": "+create database if not exists markov_demo;", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 2, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 3, - "Type": 2, - "Content": "+use markov_demo;", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 4, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 5, - "Type": 2, - "Content": "+CREATE TABLE `got_testcase` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 6, - "Type": 2, - "Content": "+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 7, - "Type": 2, - "Content": "+ `scenario_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'scenario id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 8, - "Type": 2, - "Content": "+ `gmt_create` datetime DEFAULT NULL COMMENT '创建时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 9, - "Type": 2, - "Content": "+ `gmt_modified` datetime DEFAULT NULL COMMENT '修改时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 10, - "Type": 2, - "Content": "+ `name` longtext COMMENT 'name',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 11, - "Type": 2, - "Content": "+ `description` longtext COMMENT 'description',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 12, - "Type": 2, - "Content": "+ `long_description` longtext COMMENT '详细描述',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 13, - "Type": 2, - "Content": "+ `content` longtext COMMENT '存储case的阶段数据,比如数据准备阶段,数据执行阶段',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 14, - "Type": 2, - "Content": "+ `case_group` varchar(100) DEFAULT NULL COMMENT 'case分组',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 15, - "Type": 2, - "Content": "+ `is_deleted` int(11) DEFAULT '0' COMMENT '用例是否被删除。0-没有删除;1-已删除,此类case不会展示到页面上',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 16, - "Type": 2, - "Content": "+ `case_template` text COMMENT '用例模板 java/c++',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 17, - "Type": 2, - "Content": "+ `features` text COMMENT '业务特征',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 18, - "Type": 2, - "Content": "+ `is_visible` int DEFAULT '0' COMMENT '是否可见用例',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 19, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 20, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='testcase';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 21, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 22, - "Type": 2, - "Content": "+CREATE TABLE `got_pipeline` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 23, - "Type": 2, - "Content": "+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键(id)',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 24, - "Type": 2, - "Content": "+ `pipeline` longtext COMMENT 'pipeline的json配置',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 25, - "Type": 2, - "Content": "+ `extend` text COMMENT '扩展字段',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 26, - "Type": 2, - "Content": "+ `tag` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '流程定义/自定义\\n',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 27, - "Type": 2, - "Content": "+ `scenario_id` bigint(20) unsigned DEFAULT NULL COMMENT '场景id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 28, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 29, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='存储流程执行的pipeline配置文件';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 30, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 31, - "Type": 2, - "Content": "+CREATE TABLE `got_scenario` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 32, - "Type": 2, - "Content": "+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 33, - "Type": 2, - "Content": "+ `name` varchar(100) DEFAULT NULL COMMENT 'name',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 34, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 35, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='测试场景表';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 36, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 37, - "Type": 2, - "Content": "+CREATE TABLE `got_envs` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 38, - "Type": 2, - "Content": "+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 39, - "Type": 2, - "Content": "+ `gmt_create` datetime DEFAULT NULL COMMENT '创建时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 40, - "Type": 2, - "Content": "+ `gmt_modified` datetime DEFAULT NULL COMMENT '修改时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 41, - "Type": 2, - "Content": "+ `host_ip` varchar(20) DEFAULT NULL COMMENT 'host_ip',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 42, - "Type": 2, - "Content": "+ `status` varchar(20) DEFAULT NULL COMMENT '状态',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 43, - "Type": 2, - "Content": "+ `name` varchar(200) DEFAULT NULL COMMENT '环境名称',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 44, - "Type": 2, - "Content": "+ `env_detail` text COMMENT '环境详情',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 45, - "Type": 2, - "Content": "+ `scenario_id` bigint(20) unsigned DEFAULT NULL COMMENT '场景id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 46, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 47, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=6928 DEFAULT CHARSET=utf8 COMMENT='环境列表';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 48, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 49, - "Type": 2, - "Content": "+CREATE TABLE `pipeline_ui` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 50, - "Type": 2, - "Content": "+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 51, - "Type": 2, - "Content": "+ `scenario_id` bigint(20) unsigned DEFAULT NULL COMMENT '场景id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 52, - "Type": 2, - "Content": "+ `content` text COMMENT 'pipeline_ui的jsonString\\n',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 53, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 54, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='pipeline_ui表';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 55, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 56, - "Type": 2, - "Content": "+CREATE TABLE `got_datasource` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 57, - "Type": 2, - "Content": "+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键/场景id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 58, - "Type": 2, - "Content": "+ `content` longtext COMMENT '数据源内容',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 59, - "Type": 2, - "Content": "+ `scenario_id` bigint(20) unsigned DEFAULT NULL COMMENT '场景id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 60, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`),", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 61, - "Type": 2, - "Content": "+ KEY `idx_scenario_id` (`scenario_id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 62, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='测试数据源表';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 63, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 64, - "Type": 2, - "Content": "+CREATE TABLE `got_menu` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 65, - "Type": 2, - "Content": "+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 66, - "Type": 2, - "Content": "+ `content` text COMMENT 'menu的jsonString\\n',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 67, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 68, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='menu表';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 69, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 70, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 71, - "Type": 2, - "Content": "+insert into got_menu values(0, \"{ \\\"buinfo\\\": { \\\"buid\\\": 1, \\\"appSecneMap\\\": { \\\"1\\\": \\\"1\\\" }, \\\"menu\\\": [{ \\\"businessId\\\": 1, \\\"businessName\\\": \\\"markov-demo\\\", \\\"appMenuList\\\": [{ \\\"appName\\\": \\\"测试模块\\\", \\\"appId\\\": 1, \\\"scenarioMenuList\\\": [{ \\\"isMember\\\": true, \\\"scenarioId\\\": 1, \\\"scenarioName\\\": \\\"场景1\\\" },{ \\\"isMember\\\": true, \\\"scenarioId\\\": 2, \\\"scenarioName\\\": \\\"场景2\\\" }] }] }, ], \\\"buName\\\": \\\"markov-demo\\\" }}\");", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 72, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 73, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 74, - "Type": 2, - "Content": "+CREATE TABLE `got_reports` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 75, - "Type": 2, - "Content": "+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 76, - "Type": 2, - "Content": "+ `gmt_create` datetime NOT NULL COMMENT '创建时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 77, - "Type": 2, - "Content": "+ `gmt_modified` datetime NOT NULL COMMENT '修改时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 78, - "Type": 2, - "Content": "+ `user` text COMMENT '执行用户',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 79, - "Type": 2, - "Content": "+ `report_name` text COMMENT '报告名称',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 80, - "Type": 2, - "Content": "+ `status` varchar(100) DEFAULT NULL COMMENT '执行状态',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 81, - "Type": 2, - "Content": "+ `message` text COMMENT '信息',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 82, - "Type": 2, - "Content": "+ `app_id` bigint(20) unsigned DEFAULT NULL COMMENT 'appid',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 83, - "Type": 2, - "Content": "+ `scenario_id` bigint(20) unsigned DEFAULT NULL COMMENT '场景id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 84, - "Type": 2, - "Content": "+ `run_type` text COMMENT '执行方式',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 85, - "Type": 2, - "Content": "+ `exec_id` text COMMENT '批次id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 86, - "Type": 2, - "Content": "+ `analysis` text COMMENT '分析报告',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 87, - "Type": 2, - "Content": "+ `task_id` text COMMENT 'zk任务id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 88, - "Type": 2, - "Content": "+ `zk_info` longtext COMMENT 'zk信息',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 89, - "Type": 2, - "Content": "+ `accuracy_report_id` bigint(20) unsigned DEFAULT NULL COMMENT '精准测试报告id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 90, - "Type": 2, - "Content": "+ `case_num` int(10) unsigned DEFAULT '0' COMMENT '回归用例数',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 91, - "Type": 2, - "Content": "+ `image_name` text COMMENT '回归的镜像版本',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 92, - "Type": 2, - "Content": "+ `branch_name` text COMMENT '执行用例的分支',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 93, - "Type": 2, - "Content": "+ `git_branch` text COMMENT '测试源码的分支',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 94, - "Type": 2, - "Content": "+ `git_commit` text COMMENT '测试源码的commit版本',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 95, - "Type": 2, - "Content": "+ `cc_cov_rate` text COMMENT '增量代码覆盖率',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 96, - "Type": 2, - "Content": "+ `is_visible` int DEFAULT '0' COMMENT '是否可见报告',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 97, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`),", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 98, - "Type": 2, - "Content": "+ KEY `idx_scenarioid` (`scenario_id`),", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 99, - "Type": 2, - "Content": "+ KEY `idx_appid` (`app_id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 100, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=7858 DEFAULT CHARSET=utf8mb4 COMMENT='回归测试报告表';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 101, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 102, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 103, - "Type": 2, - "Content": "+CREATE TABLE `got_testcase_snaps` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 104, - "Type": 2, - "Content": "+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 105, - "Type": 2, - "Content": "+ `gmt_create` datetime NOT NULL COMMENT '创建时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 106, - "Type": 2, - "Content": "+ `gmt_modified` datetime NOT NULL COMMENT '修改时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 107, - "Type": 2, - "Content": "+ `scenario_id` bigint(20) unsigned DEFAULT NULL COMMENT '场景id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 108, - "Type": 2, - "Content": "+ `app_id` bigint(20) unsigned DEFAULT NULL COMMENT 'appid',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 109, - "Type": 2, - "Content": "+ `name` varchar(100) DEFAULT NULL COMMENT '用例名',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 110, - "Type": 2, - "Content": "+ `description` text COMMENT '描述',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 111, - "Type": 2, - "Content": "+ `long_description` longtext COMMENT '详情',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 112, - "Type": 2, - "Content": "+ `content` longtext COMMENT '输入,输出,期望,数据准备',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 113, - "Type": 2, - "Content": "+ `status` varchar(100) DEFAULT NULL COMMENT '用例执行状态',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 114, - "Type": 2, - "Content": "+ `testreport_id` bigint(20) unsigned NOT NULL COMMENT '归属的报告id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 115, - "Type": 2, - "Content": "+ `testcase_id` bigint(20) unsigned NOT NULL COMMENT '归属的用例id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 116, - "Type": 2, - "Content": "+ `case_group` varchar(100) DEFAULT NULL COMMENT '测试用例分组',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 117, - "Type": 2, - "Content": "+ `tag` varchar(100) DEFAULT NULL COMMENT 'case标签,可有有多个值',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 118, - "Type": 2, - "Content": "+ `version` varchar(100) DEFAULT NULL COMMENT 'case版本号',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 119, - "Type": 2, - "Content": "+ `run_time` bigint(20) unsigned DEFAULT NULL COMMENT '执行时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 120, - "Type": 2, - "Content": "+ `run_time_str` text COMMENT '执行时间标准化',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 121, - "Type": 2, - "Content": "+ `retry_num` bigint(20) unsigned DEFAULT NULL COMMENT '重试次数',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 122, - "Type": 2, - "Content": "+ `constancy` text COMMENT '稳定性',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 123, - "Type": 2, - "Content": "+ `env_name` text COMMENT '环境名',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 124, - "Type": 2, - "Content": "+ `conflict_desc` text COMMENT '冲突用例描述',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 125, - "Type": 2, - "Content": "+ `is_parallel` tinyint(1) DEFAULT NULL COMMENT '是否串行',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 126, - "Type": 2, - "Content": "+ `trouble_shoot_box` longtext COMMENT '智能归因',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 127, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`),", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 128, - "Type": 2, - "Content": "+ KEY `idx_caseid` (`testcase_id`),", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 129, - "Type": 2, - "Content": "+ KEY `idx_reportid` (`testreport_id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 130, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=303953 DEFAULT CHARSET=utf8mb4 COMMENT='测试报告用例集快照'", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 131, - "Type": 2, - "Content": "+;", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 132, - "Type": 2, - "Content": "+CREATE TABLE `got_features_pool` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 133, - "Type": 2, - "Content": "+ `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 134, - "Type": 2, - "Content": "+ `gmt_create` datetime NOT NULL COMMENT '创建时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 135, - "Type": 2, - "Content": "+ `gmt_modified` datetime NOT NULL COMMENT '修改时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 136, - "Type": 2, - "Content": "+ `scenario_id` bigint unsigned NULL COMMENT 'scenario_id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 137, - "Type": 2, - "Content": "+ `app_id` bigint unsigned NULL COMMENT 'app_id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 138, - "Type": 2, - "Content": "+ `features` text NULL COMMENT '特征集',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 139, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 140, - "Type": 2, - "Content": "+) DEFAULT CHARACTER SET=utf8mb4 COMMENT='特征池';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 141, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 142, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 143, - "Type": 2, - "Content": "+CREATE TABLE `got_case_generate_task` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 144, - "Type": 2, - "Content": "+ `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 145, - "Type": 2, - "Content": "+ `gmt_create` datetime NOT NULL COMMENT '创建时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 146, - "Type": 2, - "Content": "+ `gmt_modified` datetime NOT NULL COMMENT '修改时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 147, - "Type": 2, - "Content": "+ `creator` text COMMENT '任务创建者',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 148, - "Type": 2, - "Content": "+ `seed_case_list` text COMMENT '种子用例id列表,以”,“分隔',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 149, - "Type": 2, - "Content": "+ `scenario_id` bigint unsigned DEFAULT NULL COMMENT '场景id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 150, - "Type": 2, - "Content": "+ `env_info` text COMMENT '测试环境信息',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 151, - "Type": 2, - "Content": "+ `feature_conf` longtext COMMENT '任务相关配置,jsonObject',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 152, - "Type": 2, - "Content": "+ `task_name` text COMMENT '任务名',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 153, - "Type": 2, - "Content": "+ `task_snap` longtext COMMENT '任务生成信息',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 154, - "Type": 2, - "Content": "+ `task_result` longtext COMMENT '最终生成用例',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 155, - "Type": 2, - "Content": "+ `task_status` text COMMENT 'crate 、executing、success or fail ',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 156, - "Type": 2, - "Content": "+ `gene_bank_snap` longtext COMMENT 'json格式gene bank',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 157, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 158, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=98 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='用例智能生成任务记录表';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 159, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 160, - "Type": 2, - "Content": "+CREATE TABLE `got_case_accuracy` (", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 161, - "Type": 2, - "Content": "+ `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 162, - "Type": 2, - "Content": "+ `gmt_create` datetime NOT NULL COMMENT '创建时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 163, - "Type": 2, - "Content": "+ `gmt_modified` datetime NOT NULL COMMENT '修改时间',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 164, - "Type": 2, - "Content": "+ `case_id` bigint unsigned DEFAULT NULL COMMENT 'case id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 165, - "Type": 2, - "Content": "+ `exe_id` bigint unsigned DEFAULT NULL COMMENT '回归执行id',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 166, - "Type": 2, - "Content": "+ `cov_line` longtext COMMENT 'case覆盖的代码行,json格式',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 167, - "Type": 2, - "Content": "+ `collect_type` text COMMENT 'single : 单case收集;total:任务整体收集',", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 168, - "Type": 2, - "Content": "+ PRIMARY KEY (`id`),", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 169, - "Type": 2, - "Content": "+ KEY `idx_caseid` (`case_id`),", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 170, - "Type": 2, - "Content": "+ KEY `idx_exe_id` (`exe_id`)", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 171, - "Type": 2, - "Content": "+) ENGINE=InnoDB AUTO_INCREMENT=16001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='case精准数据覆盖数据记录表';", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 172, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 173, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 174, - "Type": 2, - "Content": "+INSERT INTO `got_testcase` (`gmt_create`,`gmt_modified`,`scenario_id`,`name`,`description`,`long_description`,`content`,`case_group`,`is_deleted`,`case_template`,`is_visible`) VALUES ('2020-04-28 19:12:55','2020-04-28 19:12:55',1,'case名','用例智能生成-种子用例','种子用例','{\\\"prepareData\\\":[{\\\"Tair\\\":[{\\\"dsName\\\":\\\"table.markovtair.test\\\",\\\"data\\\":[{\\\"key\\\":\\\"testkey\\\",\\\"value\\\":\\\"testvalue\\\",\\\"property\\\":\\\"\\\"}]}]}],\\\"caseRunStage\\\":[{\\\"group_name\\\":\\\"ERPC校验(第一组)\\\",\\\"data\\\":[{\\\"input\\\":\\\"{\\\\n \\\\\\\"ad_id\\\\\\\": \\\\\\\"222\\\\\\\",\\\\n \\\\\\\"search_key\\\\\\\": \\\\\\\"key1\\\\\\\",\\\\n \\\\\\\"match_level\\\\\\\": 2,\\\\n \\\\\\\"user_type\\\\\\\": \\\\\\\"type1\\\\\\\",\\\\n \\\\\\\"top_num\\\\\\\": 10,\\\\n \\\\\\\"use_feature\\\\\\\": false,\\\\n \\\\\\\"other1\\\\\\\": \\\\\\\"1\\\\\\\",\\\\n \\\\\\\"other2\\\\\\\": \\\\\\\"0\\\\\\\"\\\\n}\\\",\\\"expect\\\":\\\"{\\\\n \\\\\\\"result\\\\\\\": \\\\\\\"1\\\\\\\" \\\\n}\\\",\\\"actual\\\":\\\"null\\\"}]}]}','test',0,'c++',0);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 175, - "Type": 2, - "Content": "+INSERT INTO `got_testcase` (`gmt_create`,`gmt_modified`,`scenario_id`,`name`,`description`,`long_description`,`content`,`case_group`,`is_deleted`,`case_template`,`is_visible`) VALUES ('2020-04-28 19:12:55','2020-04-28 19:12:55',1,'case名','用例智能推荐用例1','普通用例','{\\\"prepareData\\\":[{\\\"Tair\\\":[{\\\"dsName\\\":\\\"table.markovtair.test\\\",\\\"data\\\":[{\\\"key\\\":\\\"testkey\\\",\\\"value\\\":\\\"testvalue\\\",\\\"property\\\":\\\"\\\"}]}],\\\"Imock\\\":[{\\\"dsName\\\":\\\"erpc_merger_inner\\\",\\\"data\\\":[{\\\"key\\\":\\\"key1\\\",\\\"value\\\":\\\"value1\\\",\\\"property\\\":\\\"\\\"},{\\\"key\\\":\\\"key2\\\",\\\"value\\\":\\\"value2\\\",\\\"property\\\":\\\"\\\"}],\\\"restartFlag\\\":\\\"0\\\"}]}],\\\"caseRunStage\\\":[{\\\"group_name\\\":\\\"ERPC校验(第一组)\\\",\\\"data\\\":[{\\\"input\\\":\\\"{\\\\n \\\\\\\"param_manager\\\\\\\": {\\\\n \\\\\\\"expand_param\\\\\\\": {\\\\n \\\\\\\"key_value_list\\\\\\\": [\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature1\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"true\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature2\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"3,8;4,16\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature3\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"1\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature4\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"one_phase_model_searching,200,166,1\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature5\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"false\\\\\\\"\\\\n }\\\\n ]\\\\n }\\\\n }\\\\n}\\\",\\\"expect\\\":\\\"{\\\\n \\\\\\\"result\\\\\\\": \\\\\\\"1\\\\\\\"\\\\n}\\\",\\\"actual\\\":\\\"null\\\"}]}]}','猜你喜欢',0,'c++',0);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 176, - "Type": 2, - "Content": "+INSERT INTO `got_testcase` (`gmt_create`,`gmt_modified`,`scenario_id`,`name`,`description`,`long_description`,`content`,`case_group`,`is_deleted`,`case_template`,`is_visible`) VALUES ('2020-04-28 19:12:55','2020-04-28 19:12:55',1,'case名','用例智能推荐用例2','普通用例','{\\\"prepareData\\\":[{\\\"Tair\\\":[{\\\"dsName\\\":\\\"table.markovtair.test\\\",\\\"data\\\":[{\\\"key\\\":\\\"testkey\\\",\\\"value\\\":\\\"testvalue\\\",\\\"property\\\":\\\"\\\"}]}],\\\"Imock\\\":[{\\\"dsName\\\":\\\"erpc_merger_inner\\\",\\\"data\\\":[{\\\"key\\\":\\\"key1\\\",\\\"value\\\":\\\"confict-value\\\",\\\"property\\\":\\\"\\\"},{\\\"key\\\":\\\"key2\\\",\\\"value\\\":\\\"value2\\\",\\\"property\\\":\\\"\\\"}]}]}],\\\"caseRunStage\\\":[{\\\"group_name\\\":\\\"ERPC校验(第一组)\\\",\\\"data\\\":[{\\\"input\\\":\\\"{\\\\n \\\\\\\"param_manager\\\\\\\": {\\\\n \\\\\\\"expand_param\\\\\\\": {\\\\n \\\\\\\"key_value_list\\\\\\\": [\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature1\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"true\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature2\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"3,8;4,16\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature3\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"1\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature4\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"one_phase_model_searching,200,166,1\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature5\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"false\\\\\\\"\\\\n }\\\\n ]\\\\n }\\\\n }\\\\n}\\\",\\\"expect\\\":\\\"{\\\\n \\\\\\\"result\\\\\\\": \\\\\\\"1\\\\\\\"\\\\n}\\\"}]}]}','购物车',0,'c++',0);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 177, - "Type": 2, - "Content": "+INSERT INTO `got_testcase` (`gmt_create`,`gmt_modified`,`scenario_id`,`name`,`description`,`long_description`,`content`,`case_group`,`is_deleted`,`case_template`,`is_visible`) VALUES ('2020-04-28 19:12:55','2020-04-28 19:12:55',1,'case名','用例智能推荐用例3','普通用例','{\\\"prepareData\\\":[{\\\"Tair\\\":[{\\\"dsName\\\":\\\"table.markovtair.test\\\",\\\"data\\\":[{\\\"key\\\":\\\"testkey\\\",\\\"value\\\":\\\"testvalue\\\",\\\"property\\\":\\\"\\\"}]}],\\\"Imock\\\":[{\\\"dsName\\\":\\\"erpc_merger_inner\\\",\\\"data\\\":[{\\\"key\\\":\\\"key1\\\",\\\"value\\\":\\\"value1\\\",\\\"property\\\":\\\"\\\"},{\\\"key\\\":\\\"key3\\\",\\\"value\\\":\\\"value3\\\",\\\"property\\\":\\\"\\\"}]}]}],\\\"caseRunStage\\\":[{\\\"group_name\\\":\\\"ERPC校验(第一组)\\\",\\\"data\\\":[{\\\"input\\\":\\\"{\\\\n \\\\\\\"param_manager\\\\\\\": {\\\\n \\\\\\\"expand_param\\\\\\\": {\\\\n \\\\\\\"key_value_list\\\\\\\": [\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature1\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"true\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature2\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"3,8;4,16\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature3\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"1\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature4\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"one_phase_model_searching,200,166,1\\\\\\\"\\\\n },\\\\n {\\\\n \\\\\\\"key\\\\\\\": \\\\\\\"feature5\\\\\\\",\\\\n \\\\\\\"value\\\\\\\": \\\\\\\"false\\\\\\\"\\\\n }\\\\n ]\\\\n }\\\\n }\\\\n}\\\",\\\"expect\\\":\\\"{\\\\n \\\\\\\"result\\\\\\\": \\\\\\\"1\\\\\\\"\\\\n}\\\"}]}]}','直播',0,'c++',0);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 178, - "Type": 2, - "Content": "+", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 179, - "Type": 2, - "Content": "+INSERT INTO `got_envs` (`gmt_create`,`gmt_modified`,`scenario_id`,`name`,`status`,`host_ip`,`env_detail`) VALUES ('2020-04-28 19:12:55','2020-04-28 19:12:55',1,'初始测试环境','SUCCESS','11.167.254.210','123');", - "Comments": null, - "SectionInfo": null - } - ] - } - ], - "IsIncomplete": false - }, - { - "Name": "src/main/resources/static/index.html", - "OldName": "src/main/resources/static/index.html", - "Index": 6, - "Addition": 1, - "Deletion": 1, - "Type": 2, - "IsCreated": false, - "IsDeleted": false, - "IsBin": false, - "IsLFSFile": false, - "IsRenamed": false, - "IsSubmodule": false, - "Sections": [ - { - "Name": "", - "Lines": [ - { - "LeftIdx": 0, - "RightIdx": 0, - "Type": 4, - "Content": "@@ -24,7 +24,7 @@", - "Comments": null, - "SectionInfo": { - "Path": "src/main/resources/static/index.html", - "LastLeftIdx": 0, - "LastRightIdx": 0, - "LeftIdx": 24, - "RightIdx": 24, - "LeftHunkSize": 7, - "RightHunkSize": 7 - } - }, - { - "LeftIdx": 24, - "RightIdx": 24, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 25, - "RightIdx": 25, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 26, - "RightIdx": 26, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 27, - "RightIdx": 0, - "Type": 3, - "Content": "- ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 0, - "RightIdx": 27, - "Type": 2, - "Content": "+ ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 28, - "RightIdx": 28, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 29, - "RightIdx": 29, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 30, - "RightIdx": 30, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - } - ] - }, - { - "Name": "", - "Lines": [ - { - "LeftIdx": 0, - "RightIdx": 0, - "Type": 4, - "Content": " ", - "Comments": null, - "SectionInfo": { - "Path": "src/main/resources/static/index.html", - "LastLeftIdx": 30, - "LastRightIdx": 30, - "LeftIdx": 43, - "RightIdx": 43, - "LeftHunkSize": 0, - "RightHunkSize": 0 - } - } - ] - } - ], - "IsIncomplete": false - }, - { - "Name": "src/test/java/com/alibaba/markovdemo/MarkovDemoApplicationTests.java", - "OldName": "src/test/java/com/alibaba/markovdemo/MarkovDemoApplicationTests.java", - "Index": 7, - "Addition": 0, - "Deletion": 27, - "Type": 2, - "IsCreated": false, - "IsDeleted": false, - "IsBin": false, - "IsLFSFile": false, - "IsRenamed": false, - "IsSubmodule": false, - "Sections": [ - { - "Name": "", - "Lines": [ - { - "LeftIdx": 0, - "RightIdx": 0, - "Type": 4, - "Content": "@@ -32,36 +32,9 @@ class MarkovDemoApplicationTests {", - "Comments": null, - "SectionInfo": { - "Path": "src/test/java/com/alibaba/markovdemo/MarkovDemoApplicationTests.java", - "LastLeftIdx": 0, - "LastRightIdx": 0, - "LeftIdx": 32, - "RightIdx": 32, - "LeftHunkSize": 36, - "RightHunkSize": 9 - } - }, - { - "LeftIdx": 32, - "RightIdx": 32, - "Type": 1, - "Content": " \t\treturn df2.format(date1);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 33, - "RightIdx": 33, - "Type": 1, - "Content": " \t}", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 34, - "RightIdx": 34, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 35, - "RightIdx": 0, - "Type": 3, - "Content": "-", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 36, - "RightIdx": 35, - "Type": 1, - "Content": " \t@Test", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 37, - "RightIdx": 36, - "Type": 1, - "Content": " \tvoid wordTest () throws IOException {", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 38, - "RightIdx": 37, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 39, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\t// FileInputStream fis = new FileInputStream(\"199801.txt\");", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 40, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\t// FileOutputStream fos = new FileOutputStream(\"dic.txt\");", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 41, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\t// ImportCorpus readF = new ImportCorpus(fis, fos);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 42, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\t// readF.readDic();", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 43, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\t// System.out.println(\"µ¼Èë½áÊø\");", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 44, - "RightIdx": 0, - "Type": 3, - "Content": "-", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 45, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tString filename = \"dic.txt\";", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 46, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tHashMap hm = new HashMap();", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 47, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tHashMap len = new HashMap();", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 48, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tGenerateDictionary genDic = new GenerateDictionary();", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 49, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tSegmentation seg;", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 50, - "RightIdx": 0, - "Type": 3, - "Content": "-", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 51, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tgenDic.genHashDic(filename, hm, len);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 52, - "RightIdx": 0, - "Type": 3, - "Content": "-", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 53, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tInputStreamReader reader = new InputStreamReader(System.in);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 54, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tBufferedReader br = new BufferedReader(reader);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 55, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tString data = \"\";", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 56, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tdata = br.readLine();", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 57, - "RightIdx": 0, - "Type": 3, - "Content": "-", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 58, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tseg = new Segmentation(hm, len);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 59, - "RightIdx": 0, - "Type": 3, - "Content": "-", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 60, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tString FmmTarget = seg.Fmm(data);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 61, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tString BmmTarget = seg.Bmm(data);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 62, - "RightIdx": 0, - "Type": 3, - "Content": "-", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 63, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tSystem.out.println(\"FmmTarget: \" + FmmTarget);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 64, - "RightIdx": 0, - "Type": 3, - "Content": "-\t\tSystem.out.println(\"BmmTarget: \" + BmmTarget);", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 65, - "RightIdx": 38, - "Type": 1, - "Content": " \t}", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 66, - "RightIdx": 39, - "Type": 1, - "Content": " ", - "Comments": null, - "SectionInfo": null - }, - { - "LeftIdx": 67, - "RightIdx": 40, - "Type": 1, - "Content": " }", - "Comments": null, - "SectionInfo": null - } - ] - } - ], - "IsIncomplete": false - } - ] -} -``` ---- - -### 点赞 -``` -POST /api/projects/:id/praise_tread/like -``` -*示例* -``` -curl -X POST http://localhost:3000/api/projects/3263/praise_tread/like | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是 |int |项目id | - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int|0:点赞成功,-1:操作失败,2:表示已经点过赞了| - - -返回值 -``` -{ - "status": 0, - "message": "success" -} -``` ---- - -### 取消点赞 -``` -DELETE /api/projects/:id/praise_tread/unlike -``` -*示例* -``` -curl -X DELETE http://localhost:3000/api/projects/3263/praise_tread/unlike | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是 |int |项目id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int|0:点赞成功,-1:操作失败,2:表示还未点赞| - - -返回值 -``` -{ - "status": 0, - "message": "success" -} -``` ---- - -### 用户是否点过赞 -``` -GET /api/projects/:id/praise_tread/check_like -``` -*示例* -``` -curl -X GET http://localhost:3000/api/projects/3263/praise_tread/check_like | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是 |int |项目id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int|1:已点过赞,0:未点过赞, -1:请求操作失败| - - -返回值 -``` -{ - "status": 0, - "message": "success" -} -``` ---- - -### 项目的点赞者列表 -``` -GET /api/projects/:id/praise_tread -``` -*示例* -``` -curl -X GET \ --d "page=1" \ --d "limit=5" \ -http://localhost:3000/api/projects/3263/praise_tread | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|page |否|string |页数,第几页 | -|limit |否|string |每页多少条数据,默认15条 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|total_count |int|总条数| -|praises |array|点赞数据| -|-- name |string|用户名称| -|-- login |string|用户标识/登录名(login)| -|-- image_url |string|用户头像| - - - -返回值 -``` -{ - "total_count": 1, - "praises": [ - { - "name": "18816895620", - "login": "18816895620", - "image_url": "avatars/User/b" - } - ] -} -``` ---- - -### 关注(项目) -``` -POST /api/projects/:id/watchers/follow -``` -*示例* -``` -curl -X POST http://localhost:3000/api/projects/3263/watchers/follow | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int|0:点赞成功,-1:操作失败,2:表示已经点过赞了| - - -返回值 -``` -{ - "status": 0, - "message": "响应成功" -} -``` ---- - -### 取消关注 -``` -DELETE /api/projects/:id/watchers/unfollow -``` -*示例* -``` -curl -X DELETE http://localhost:3000//api/projects/3263/watchers/unfollow | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int|0:点赞成功,-1:操作失败,2:表示还未点赞| - - -返回值 -``` -{ - "status": 0, - "message": "响应成功" -} -``` ---- - -### 用户是否关注过项目 -``` -GET /api/projects/:id/watchers/check_watch -``` -*示例* -``` -curl -X GET http://localhost:3000/api/projects/3263/watchers/check_watch | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是 |int |项目id | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|status |int|1:已关注,0:未关注, -1:请求操作失败| - - -返回值 -``` -{ - "status": 0, - "message": "success" -} -``` ---- - -### 项目的关注者列表 -``` -GET /api/projects/:id/watchers -``` -*示例* -``` -curl -X GET \ --d "page=1" \ --d "limit=5" \ -http://localhost:3000//api/projects/3263/watchers | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|page |否|string |页数,第几页 | -|limit |否|string |每页多少条数据,默认15条 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|total_count |int|总条数| -|watchers |array|关注数据| -|-- name |string|用户名称| -|-- login |string|用户标识/登录名(login)| -|-- image_url |string|用户头像| - - -返回值 -``` -{ - "total_count": 1, - "watchers": [ - { - "name": "18816895620", - "login": "18816895620", - "image_url": "avatars/User/b" - } - ] -} -``` ---- - -### 仓库新建文件 -``` -POST /api/repositories/:id/create_file -``` -*示例* -``` -curl -X POST \ --d 'filepath=test1_create_file1.rb' \ --d 'branch=master' \ --d 'content=提交的内容' \ --d 'message=test commit ' \ -http://localhost:3000/api/18816895620/mirror_demo/contents.json | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|string |项目id | -|filepath |是|string |文件相对于仓库的路径 | -|content |否|string |内容 | -|message |否|string |提交说明 | -|branch |否|string |分支名称, branch和new_branch必须存在一个 | -|new_branch |否|string |新的分支名称 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|name |string|文件名| -|sha |string|提交文件的sha值| -|size |int|文件大小, 单位:B| -|content |string|base64编码后的文件内容| -|encoding |string|编码方式| -|commit |object|| -|-- message |string|提交备注说明信息| -|-- committer|object|| -|---- name |string|用户名| -|---- email |string|用户邮箱| -|---- date |string|文件创建时间| - - - -返回值 -``` -{ - "name": "test1_create_file12.rb", - "sha": "7b70509105b587e71f5692b9e8ab70851e321f64", - "size": 12, - "content": "Wm5ObWMyRmtaZz09", - "encoding": "base64", - "commit": { - "message": "good luck\n", - "author": { - "name": "18816895620", - "email": "2456233122@qq.com", - "date": "2020-01-07T03:31:20Z" - }, - "committer": { - "name": "18816895620", - "email": "2456233122@qq.com", - "date": "2020-01-07T03:31:20Z" - } - } -} -``` ---- - -### 更新仓库中的文件 -``` -PUT /api/repositories/:id/update_file.json -``` -*示例* -``` -curl -X PUT \ --d 'filepath=text1.rb' \ --d 'branch=master' \ --d 'content=ruby code' \ --d 'message=更改提交信息' \ --d 'from_path=text.rb' \ --d "sha=57426eb21e4ceabdf4b206f022077e0040" \ -http://localhost:3000/api/repositories/3938/update_file.json | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|filepath |是|string |文件相对于仓库的路径(或修改后的文件路径) | -|from_path |是|string |原文件相对于仓库的路径, 只有当需要修改原文件名称时,才需要该参数 | -|sha |是|string |文件的sha标识值 | -|content |是|string |内容 | -|message |否|string |提交说明 | -|branch |否|string |分支名称, branch和new_branch必须存在一个,且只能存在一个 | -|new_branch |否|string |新的分支名称 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|name |string|文件名| -|sha |string|提交文件的sha值| -|size |int|文件大小, 单位:B| -|content |string|base64编码后的文件内容| -|encoding |string|编码方式| -|commit |object|| -|-- message |string|提交备注说明信息| -|-- committer|object|| -|---- name |string|用户名| -|---- email |string|用户邮箱| -|---- date |string|文件创建时间| - - -返回值 -``` -{ - "name": "test1_create_file6.rb", - "sha": "57426eb21e4ceabdf4b206f022257e08077e0040", - "size": 16, - "content": "5o+Q5Lqk55qE5YaF5a65MQ==", - "encoding": "base64", - "commit": { - "message": "更改提交信息\n", - "author": { - "name": "18816895620", - "email": "2456233122@qq.com", - "date": "2020-01-08T07:05:15Z" - }, - "committer": { - "name": "18816895620", - "email": "2456233122@qq.com", - "date": "2020-01-08T07:05:15Z" - } - } -} -``` ---- - -### 删除仓库中的文件 -``` -DELETE /api/repositories/:id/delete_file -``` -*示例* -``` -curl -X DELETE \ --d 'filepath=test1_create_file12.rb' \ --d 'test delete file' \ --d 'sha=7b70509105b587e71f5692b9e8ab70851e321f64' \ -http://localhost:3000/api//api/repositories/3868/delete_file | jq -``` -*请求参数说明:* - -|参数名|必选|类型|说明| -|-|-|-|-| -|id |是|int |项目id | -|filepath |是|string |文件相对于仓库的路径 | -|message |否|string |提交说明 | -|branch |否|string |分支名称, 默认为master分支| -|new_branch |否|string |新的分支名称 | - - -*返回参数说明:* - -|参数名|类型|说明| -|-|-|-| -|sha |string|提交文件的sha值| -|commit |object|| -|-- message |string|提交备注说明信息| -|-- committer|object|| -|---- name |string|用户名| -|---- email |string|用户邮箱| -|---- date |string|文件创建时间| - - -返回值 -``` -{ - "commit": { - "sha": "7b70509105b587e71f5692b9e8ab70851e321f64", - "message": "Delete 'test1_create_file11.rb'\n", - "author": { - "name": "18816895620", - "email": "2456233122@qq.com", - "date": "2020-01-08T07:57:34Z" - }, - "committer": { - "name": "18816895620", - "email": "2456233122@qq.com", - "date": "2020-01-08T07:57:34Z" - } - } -} -``` ---- +![](docs/figs/milestone.png) diff --git a/api_document.md b/api_document.md new file mode 100644 index 00000000..23a7c022 --- /dev/null +++ b/api_document.md @@ -0,0 +1,3601 @@ +--- + + +# API文档 + +## 基本介绍 + +### 开发API服务地址: + +**https://testgitea.trustie.net/** + + +响应状态说明: + +|字段|类型|说明| +|-|-|-| +|status |int |响应状态码,0:请求成功,-1: 请求失败| +|message |string |响应说明 | + + +### API接口 +--- + +#### 用户注册(通过其他平台) +``` +POST accounts/remote_register +``` +*示例* +``` +curl -X POST \ +-d "email=2456233122@qq.com" \ +-d "password=djs_D_00001" \ +-d "username=16895620" \ +-d "platform=forge" \ +http://localhost:3000/api/accounts/remote_register | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|email |是|string |邮箱 | +|username |是|string |登录名 | +|password |是|string |秘密 | +|platform |否|string |用户来源的相关平台,取值范围['educoder', 'trustie', 'forge'], 默认值为forge | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|user|json object |返回数据| +|-- id |int |用户id | +|-- token |string|用户token| + + +返回值 +``` +{ + "status": 0, + "message": "success", + "user": { + "id": 36400, + "token": "8c87a80d9cfacc92fcb2451845104f35119eda96" + } +} +``` +--- + +#### 获取当前登录用户信息 +``` +GET api/users/me +``` +*示例* +``` +curl -X GET http://localhost:3000/api/users/me | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|user_id |int |用户id | +|username |string|用户名称| +|admin |boolean|是否为管理用户| +|login |string|登录名| +|image_url |string|用户头像| + + +返回值 +``` +{ + "username": "18816895620", + "login": "18816895620", + "user_id": 36401, + "image_url": "avatars/User/b", + "admin": false +} +``` +--- + +#### 用户列表(带搜索功能) +``` +GET api/users/list +``` +*示例* +``` +curl -X GET \ +-d "limit=10" \ +-d "search=18816895620" +http://localhost:3000/api/users/list | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|page |否|int |页数,第几页 | +|limit |否|int |每页多少条数据,默认15条 | +|search |否|string |用户名、登录名匹配搜索 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int |总用户条数 | +|users |array| | +|-- username |string|用户全名| +|-- login |string|用户登录名| +|-- user_id |int|用户id| +|-- image_url |string|用户头像| + +返回值 +``` +{ + "total_count": 1, + "users": [ + { + "username": "18816895620", + "login": "18816895620", + "user_id": 36401, + "image_url": "avatars/User/b" + } + ] +} +``` +--- + +#### 获取项目类别列表(可根据名称搜素) +``` +GET api/project_categories +``` +*示例* +``` +curl -X GET \ +-d "name=大数据" \ +http://localhost:3000/api/project_categories/ | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|name |否|string |类别名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|project_categories|array |返回数据| +|-- id |int |类别id | +|-- name |string|类别名称| + + +返回值 +``` +{ + "project_categories": [ + { + "id": 1, + "name": "大数据" + } + ] +} +``` +--- + +#### 获取项目语言列表(可根据名称搜素) +``` +GET api/project_languages +``` +*示例* +``` +curl -X GET \ +-d "name=Ruby" \ +http://localhost:3000/api/project_languages/ | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|name |否|string |类别名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|project_languages|array |返回数据| +|-- id |int |语言id | +|-- name |string|语言名称| + + +返回值 +``` +{ + "project_languages": [ + { + "id": 1, + "name": "Ruby" + } + ] +} +``` +--- + +#### 获取.gitignore模板列表(可根据名称搜素) +``` +GET api/ignores +``` +*示例* +``` +curl -X GET \ +-d "name=Ada" \ +http://localhost:3000/api/ignores/ | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|name |否|string |gitignore名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|ignores|array |返回数据| +|-- id |int |id | +|-- name |string|gitignore名称| + + +返回值 +``` +{ + "ignores": [ + { + "id": 1, + "name": "Ada" + } + ] +} +``` +--- + +#### 获取开源许可证列表(可根据名称搜素) +``` +GET api/licenses +``` +*示例* +``` +curl -X GET \ +-d "name=AFL" \ +http://localhost:3000/api/licenses/ | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|name |否|string |开源许可证名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|licenses|array |返回数据| +|-- id |int |id | +|-- name |string|开源许可证名称| + + +返回值 +``` +{ + "licenses": [ + { + "id": 57, + "name": "AFL-1.2" + }, + { + "id": 76, + "name": "AFL-3.0" + }, + { + "id": 214, + "name": "AFL-1.1" + }, + { + "id": 326, + "name": "AFL-2.1" + }, + { + "id": 350, + "name": "AFL-2.0" + } + ] +} +``` +--- + +#### 创建项目 +``` +POST api/projects +``` +*示例* +``` +curl -X POST \ +-d "user_id=36401" \ +-d "name=hnfl_demo" \ +-d "description=my first project" \ +-d "repository_name=hnfl_demo" \ +-d "project_category_id=1" \ +-d "project_language_id=2" \ +-d "ignore_id=2" \ +-d "license_id=1" \ +http://localhost:3000/api/projects/ | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|user_id |是|int |用户id或者组织id | +|name |是|string |项目名称 | +|description |是|string |项目描述 | +|repository_name |是|string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 | +|project_category_id|是|int |项目类别id | +|project_language_id|是|int |项目语言id | +|ignore_id |否|int |gitignore相关id | +|license_id |否|int |开源许可证id | +|private |否|boolean|项目是否私有, true:为私有,false: 公开,默认为公开 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |id | +|name |string|项目名称| + + +返回值 +``` +{ + "id": 3240, + "name": "好项目" +} +``` +--- + +#### 新建镜像项目 +``` +POST api/projects/migrate +``` +*示例* +``` +curl -X POST \ +-d "user_id=36408" \ +-d "clone_addr=https://gitea.com/mx8090alex/golden.git" \ +-d "name=golden_mirror1" \ +-d "description=golden_mirror" \ +-d "project_category_id=1" \ +-d "project_language_id=2" \ +http://localhost:3000/api/projects/migrate.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|user_id |是|int |用户id或者组织id | +|name |是|string |项目名称 | +|clone_addr |是|string |镜像项目clone地址 | +|description |否|string |项目描述 | +|repository_name |是|string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 | +|project_category_id|是|int |项目类别id | +|project_language_id|是|int |项目语言id | +|is_mirror |否|boolean|是否设置为镜像, true:是, false:否,默认为否 | +|auth_username |否|string|镜像源仓库的登录用户名 | +|auth_password |否|string|镜像源仓库的登录秘密 | +|private |否|boolean|项目是否私有, true:为私有,false: 非私有,默认为公开 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |id | +|name |string|项目名称| + + +返回值 +``` +{ + "id": 3263, + "name": "ni项目" +} +``` + +--- +#### 手动同步镜像 +``` +POST api/repositories/:id/sync_mirror +``` +*示例* +``` +curl -X POST http://localhost:3000/api/repositories/1244/sync_mirror | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |仓库id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int |状态码, 0:标识请求成功 | +|message |string|服务端返回的信息说明| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` + +--- + +#### 项目详情 +``` +GET /api/:namespace_id/:id +``` +*示例* +``` +curl -X GET http://localhost:3000/api/jasder/jasder_test | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|namespace_id |是|string |用户登录名 | +|id |是|string |项目标识identifier | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |id | +|name |string|项目名称| +|identifier |string|项目标识| +|is_public |boolean|项目是否公开, true:公开,false:私有| +|description |string|项目简介| +|repo_id |int|仓库id| +|repo_identifier|string|仓库标识| + + +返回值 +``` +{ + "name": "ni项目", + "identifier": "mirror_demo", + "is_public": true, + "description": "my first project mirror_demo", + "repo_id": 75073, + "repo_identifier": "mirror_demo" +} +``` +--- + +#### 项目详情(简版) +``` +GET /api/:namespace_id/:id/simple +``` +*示例* +``` +curl -X GET http://localhost:3000/api/jasder/jasder_test/simple | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |id | +|name |string|项目名称| +|identifier |string|项目标识| +|is_public |boolean|项目是否公开, true:公开,false:私有| +|description |string|项目简介| +|repo_id |int|仓库id| +|repo_identifier|string|仓库标识| + + +返回值 +``` +{ + "identifier": "jasder_test", + "name": "jasder的测试项目", + "id": 4967, + "type": 0, + "author": { + "login": "jasder", + "name": "姓名", + "image_url": "avatars/User/b" + } +} +``` +--- + +#### 编辑仓库信息 +``` +GET /api/repositories/:id/edit.json +``` +*示例* +``` +curl -X GET http://localhost:3000/api/repositories/:id/edit.json | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|identifier |string |仓库标识 | +|project_id |int|项目id| +|project_name |string|项目名称| +|project_identifier |string|项目标识| +|project_description |string|项目简介| +|project_category_id |int|项目类别id| +|project_language_id |int|项目语言id| +|private |boolean|项目是否私有, true:为私有,false: 公开 | + + +返回值 +``` +{ + "identifier": "mirror_demo", + "project_id": 3263, + "project_name": "ni项目", + "project_identifier": "mirror_demo", + "project_description": "my first project mirror_demo", + "project_category_id": 1, + "project_language_id": 2, + "private": false +} +``` +--- + +#### 修改项目信息 +``` +PATCH api/projects/:id +``` +*示例* +``` +curl -X PATCH \ +-d "name=hnfl_demo" \ +-d "description=my first project" \ +-d "project_category_id=1" \ +-d "project_language_id=2" \ +-d "private=true" \ +http://localhost:3000/api/projects/3263.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|name |否|string |项目名称 | +|description |否|string |项目描述 | +|project_category_id|否|int |项目类别id | +|project_language_id|否|int |项目语言id | +|default_branch |否|string |默认分支名称 | +|private |否|boolean|项目是否私有, true:为私有,false: 公开,默认为公开 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int|id | +|identifier |string|项目标识| +|name |string|项目名称| +|description |string|项目简介| +|project_category_id|int|项目类别id| +|project_language_id|int|项目语言id| +|private |否|boolean|项目是否私有, true:为私有,false: 公开,默认为公开 | + + +返回值 +``` +{ + "id": 3263, + "identifier": "mirror_demo", + "name": "hnfl_demo", + "description": "my first project", + "project_category_id": 1, + "project_language_id": 2, + "is_public": true +} +``` +--- + +#### 删除项目 +``` +DELETE api/projects/:id +``` +*示例* +``` +curl -X DELETE http://localhost:3000/api/projects/3263.json | jq +``` + +注:只有超级管理员和项目拥有者才能删除仓库 + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|返回状态, 0: 表示操作成功 | +|message |string|返回信息说明| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +#### 项目添加成员 +``` +POST api/projects/:id/members +``` +*示例* +``` +curl -X POST \ +-d "user_id=36406" \ +http://localhost:3000/api/projects/3297/members | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|user_id |是|int |用户id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int |0:添加成功, -1: 添加失败, 1: 表示已经是项目成员 | +|message |string|返回信息说明| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +#### 项目删除成员 +``` +DELETE api/projects/:id/members/remove +``` +*示例* +``` +curl -X DELETE \ +-d "user_id=36400" \ +http://localhost:3000/api/projects/3263/members/remove | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|user_id |是|int |用户id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int |0:移除成功, -1: 移除失败, 1: 表示还不是项目成员 | +|message |string|返回信息说明| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +#### 更改项目成员角色/权限 +``` +PUT api/projects/:id/members/change_role +``` +*示例* +``` +curl -X PUT \ +-d "user_id=36400" \ +-d "role=Developer" \ +http://localhost:3000/api/projects/3263/members/change_role | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|user_id |是|int |用户id | +|role |是|string |取值范围:"Manager", "Developer", "Reporter";分别为项目管理人员(拥有所有操作权限)、项目开发人员(只拥有读写权限)、项目报告人员(只拥有读权限) | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int |0:角色更改成功, -1: 更改失败失败, 1: 表示还不是项目成员 | +|message |string|返回信息说明| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + + +#### 项目成员列表 +``` +GET api/projects/:id/members +``` +*示例* +``` +curl -X GET \ +-d "page=1" \ +-d "limit=5" \ +http://localhost:3000/api/projects/3263/members | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|page |否|string |页数,第几页 | +|limit |否|string |每页多少条数据,默认15条 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int |返回记录总条数 | +|members |array|项目成员信息| +|-- id |int|用户id| +|-- name |string|用户名称| +|-- login |string|用户登录名/标识| +|-- image_url |string|用户头像| +|-- is_owner |boolean|是否是项目的拥有者,true:是, false:不是| +|-- role |string|该用户在项目中的角色, Manager: 管理员(拥有操作权限); Developer:开发人员(只拥有读写权限); Reporter:报告人员(只拥有读权限)| + + +返回值 +``` +{ + "total_count": 2, + "members": [ + { + "id": 36401, + "name": "18816895620", + "login": "18816895620", + "image_url": "avatars/User/b", + "is_owner": true, + "role": "Manager" + }, + { + "id": 36399, + "name": "18816365620", + "login": "18816365620", + "image_url": "avatars/User/b", + "is_owner": false, + "role": "Developer" + } + ] +} +``` +--- + +#### Fork项目 +``` +POST /api/projects/:project_id/forks +``` +*示例* +``` +curl -X POST http://localhost:3000/api/projects/3297/forks | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|project_id |是|int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |项目id | +|identifier |string|项目标识| + + +返回值 +``` +{ + "id": 3290, + "identifier": "newadm" +} +``` +--- + +#### 获取代码目录列表 +``` +POST /api/:namespace_id/:project_id/repository/entries +``` +*示例* +``` +curl -X GET \ +-d "ref=develop" \ +http://localhost:3000//api/jasder/jasder_test/repository/entries | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|ref |否|string |分支名称、tag名称或是提交记录id,默认为master分支 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|last_commit |object | | +|-- commit |object | | +|id |int |id | +|name |string|文件夹或文件名称| +|path |string|文件夹或文件相对路径| +|type |string|文件类型, file:文件,dir:文件目录| +|size |int|文件夹或文件大小 单位B| +|content |string|文件内容,| +|target |string|标签| + +返回值 +```json +{ + "last_commit": { + "commit": { + "sha": "3f2de4f78d2d7050486535082cd11cdfc9f3679e", + "url": "http://localhost:3003//api/repositories/api-cloud-platform/commits/3f2de4f78d2d7050486535082cd11cdfc9f3679e", + "message": "update README.md.", + "author": { + "name": "Gitee", + "email": "noreply@gitee.com", + "date": "2020-03-02T20:23:18+08:00" + }, + "committer": { + "name": "Gitee", + "email": "noreply@gitee.com", + "date": "2020-03-02T20:23:18+08:00" + }, + "timestamp": 1583151798, + "time_from_now": "3个月前" + }, + "author": null, + "committer": null + }, + "entries": [ + { + "name": "ace-gate", + "path": "ace-gate", + "sha": "c83f85fc63b14edcd6fc502eee9996f5a9993eca", + "type": "dir", + "size": 0, + "content": null, + "target": null, + "commit": { + "message": "v2.9 升级alibaba组件release版本\n", + "sha": "6117eaab86f71115f42f2a46ff1683015cda798d", + "created_at": "1970-01-01 08:00", + "time_from_now": "51年前", + "created_at_unix": null + } + }, + { + "name": "ace-sidecar", + "path": "ace-sidecar", + "sha": "38e41d7810876b464f8f1adcbf998e1b04f710a7", + "type": "dir", + "size": 0, + "content": null, + "target": null, + "commit": { + "message": "[Feature] 升级spring 版本&consul注册中心\n", + "sha": "c0a5dde35cfc87f7dbaf676aac397b184ba0e55b", + "created_at": "1970-01-01 08:00", + "time_from_now": "51年前", + "created_at_unix": null + } + }, + ... + ] +} +``` +--- + +#### 获取子目录代码列表/编辑某个具体的文件 +``` +GET /api/repositories/:id/sub_entries +``` +*示例* +``` +curl -X GET \ +-d "ref=master" \ +-d "filepath=test1_create_file.rb" \ +http://localhost:3000/api/repositories/87/sub_entries.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|filepath |是|string |文件夹、文件的相对路径 | +|ref |否|string |分支名称、tag名称或是提交记录id,默认为master分支 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |id | +|name |string|文件夹或文件名称| +|path |string|文件夹或文件相对路径| +|type |string|文件类型, file:文件,dir:文件目录| +|size |int|文件夹或文件大小 单位KB| +|content |string|文件内容,| +|target |string|标签| +|url |string|文件访问链接,带分支| +|html_url |string|文件访问链接,未标识分支| +|git_url |string|文件夹或文件的git仓库访问链接| +|download_url |string|文件下载、文件内容访问链接| + +返回值 +```json +[ + { + "name": "build.rc", + "path": "lib/build.rc", + "type": "", + "size": 1268, + "content": null, + "target": null, + "url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/contents/lib/build.rc?ref=master", + "html_url": "http://localhost:3003/18816895620/mirror_demo/src/branch/master/lib/build.rc", + "git_url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/git/blobs/191fcf1a63b3777e2977fcede7dd5309efdd70fe", + "download_url": null + }, + { + "name": "cfg.rc", + "path": "lib/cfg.rc", + "type": "file", + "size": 107, + "content": null, + "target": null, + "url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/contents/lib/cfg.rc?ref=master", + "html_url": "http://localhost:3003/18816895620/mirror_demo/src/branch/master/lib/cfg.rc", + "git_url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/git/blobs/0b91ba0ed1c00e130c77bb9058af3787fea986a0", + "download_url": "http://localhost:3003/18816895620/mirror_demo/raw/branch/master/lib/cfg.rc" + }, + { + "name": "fn", + "path": "lib/fn", + "type": "dir", + "size": 0, + "content": null, + "target": null, + "url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/contents/lib/fn?ref=master", + "html_url": "http://localhost:3003/18816895620/mirror_demo/src/branch/master/lib/fn", + "git_url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/git/blobs/e33bd45949ef8f804471d0b6b2c59728eb445989", + "download_url": null + } +] +``` +--- + +#### 项目类别列表(用于项目列表左侧导航中的项目类别列表) +``` +GET api/project_categories/group_list +``` +*示例* +``` +curl -X GET http://localhost:3000/api/project_categories/group_list | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |项目分类id | +|name |string|项目分类名称| +|projects_count |int |项目数量| + + +返回值 +``` +[ + { + "id": 1, + "name": "大数据", + "projects_count": 30 + }, + { + "id": 2, + "name": "机器学习", + "projects_count": 1 + }, + { + "id": 3, + "name": "深度学习", + "projects_count": 1 + } +] +``` +--- + +#### 项目类型列表(用于项目列表左侧导航上方中的项目类型列表) +``` +GET api/projects/group_type_list +``` +*示例* +``` +curl -X GET http://localhost:3000/api/projects/group_type_list | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|project_type |string|项目类型 | +|name |string|项目类型名称| +|projects_count |int |项目数量| + + +返回值 +``` +[ + { + "project_type": "common", + "name": "开源托管项目", + "projects_count": 2106 + }, + { + "project_type": "mirror", + "name": "开源镜像项目", + "projects_count": 1 + } +] +``` +--- + +#### 项目列表 +``` +GET api/projects +``` +*示例* +``` +curl -X GET \ +-d "page=1" \ +-d "limit=5" \ +http://localhost:3000/api/projects | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|page |否|string |页数,第几页 | +|limit |否|string |每页多少条数据,默认15条 | +|sort_by |否|string |排序类型, 取值:updated_on \| created_on \| forked_count \| praises_count, updated_on: 更新时间排序,created_on: 创建时间排序,forked_count: fork数据排序,praises_count: 点赞数量排序,默认为updated_on更新时间排序 | +|sort_direction|否|string |排序方式,取值为: desc \| asc; desc: 降序排序, asc: 升序排序, 默认为:desc | +|search |否|string |按照项目名称搜索 | +|category_id |否|int |项目类别id | +|language_id |否|int |项目语言id | +|project_type |否|string |项目类型, 取值为:common \| mirror; common:开源托管项目, mirror:开源镜像项目 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int |项目总条数 | +|id |string |项目id | +|name |string|项目名称| +|description |string|项目简介| +|visits |int|流量数| +|forked_count |int|被fork的数量| +|praises_count |int|star数量| +|is_public |boolean|是否公开, true:公开,false:未公开| +|mirror_url |string|镜像url| +|last_update_time|int|最后更新时间,为UNIX格式的时间戳| +|author |object|项目创建者| +|-- name |string|用户名,也是用户标识| +|category |object|项目类别| +|-- id |int|项目类型id| +|-- name |string|项目类型名称| +|language |object|项目语言| +|-- id |int|项目语言id| +|-- name |string|项目语言名称| + + +返回值 +``` +{ + "total_count": 3096, + "projects": [ + { + "id": 1, + "name": "hnfl_demo1", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": null, + "last_update_time": 1577697461, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + }, + { + "id": 2, + "name": "hnfl_demo", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": null, + "last_update_time": 1577697403, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + }, + { + "id": 3, + "name": "统计局", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": null, + "last_update_time": 1577415173, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + }, + { + "id": 5, + "name": "开源同名", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": false, + "mirror_url": "https://gitea.com/CasperVector/slew.git", + "last_update_time": 1577346228, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + }, + { + "id": 7, + "name": "开源支持", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": null, + "last_update_time": 1577341572, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + } + ] +} +``` +--- + +#### 推荐项目 +``` +GET api/projects/recommend +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/projects/recommend | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int |项目总条数 | +|id |string |项目id | +|name |string|项目名称| +|description |string|项目简介| +|visits |int|流量数| +|forked_count |int|被fork的数量| +|praises_count |int|star数量| +|is_public |boolean|是否公开, true:公开,false:未公开| +|mirror_url |string|镜像url| +|last_update_time|int|最后更新时间,为UNIX格式的时间戳| +|author |object|项目创建者| +|-- name |string|用户名,也是用户标识| +|category |object|项目类别| +|-- id |int|项目类型id| +|-- name |string|项目类型名称| +|language |object|项目语言| +|-- id |int|项目语言id| +|-- name |string|项目语言名称| + + +返回值 +``` +[ + { + "id": 20, + "repo_id": null, + "identifier": "PNAekinmH", + "name": "FNILL", + "visits": 13567, + "author": { + "name": "王一达", + "login": "wangyida", + "image_url": "avatars/User/b" + }, + "category": { + "id": 8, + "name": "其他" + } + }, + ... +] + +``` +--- + +#### 项目主页 +``` +GET api/:namespace_id/:id/about +``` + +*示例* +``` +curl -X GET \ +http://localhost:3000/api/:jason/forgeplus/about | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|namespace_id |是|string |用户登录名 | +|id |是|string |项目标识identifier | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|identifier |string|project's identifier| +|content |string|主页内容| +|attachments |array|附件| +|-- name |string|用户名,也是用户标识| + + +返回值 +``` +{ + "content": "", + "identifier": "forgeplus", + attachments: [ + + ] +} + +``` +--- + +#### 修改项目主页内容 +``` +POST api/:namespace_id/:id/about +``` + +*示例* +``` +curl -X POST \ +-d "content=内容" \ +-d "attachment_ids=[1, 2, 2]" \ +http://localhost:3000/api/:jasder/forgeplus/about | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|namespace_id |是|string |用户登录名 | +|id |是|string |项目标识identifier | +|content |是|string |内容信息 | +|attachment_ids |是|array |附件id | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|identifier |string|project's identifier| +|content |string|主页内容| +|attachments |array|附件| +|-- name |string|用户名,也是用户标识| + +返回值 +``` +{ + "content": "", + "identifier": "forgeplus", + attachments: [ + + ] +} + +``` +--- + +### 获取分支列表 +``` +GET /api/:namespace_id/:id/branches +``` +*示例* +``` +curl -X GET http://localhost:3000/api/jasder/jasder_test/branches | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|id |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|name |string|分支名称| +|user_can_push |boolean|用户是否可push| +|user_can_merge |boolean|用户是否客merge| +|protected |boolean|是否为保护分支| +|http_url |boolean|http链接| +|zip_url |boolean|zip包下载链接| +|tar_url |boolean|tar.gz下载链接| +|last_commit |object|最后提交记录| +|-- id |string|提交记录id| +|-- message |string|提交的说明信息| +|-- timestamp |int|提交时间,为UNIX时间戳| +|-- time_from_now|string|转换后的时间| +|author |object|提交用户| +|-- login |string|用户名称| +|-- image_url |string|用户头像| + + +返回值 +``` +[ + { + "name": "develop", + "user_can_push": true, + "user_can_merge": true, + "protected": false, + "http_url": "http://localhost:3003/18816895620/mirror_demo.git", + "zip_url": "http://localhost:3003/18816895620/mirror_demo/develop.zip", + "tar_url": "http://localhost:3003/18816895620/mirror_demo/develop.tar.gz", + "last_commit": { + "id": "735674d6696bddbafa993db9c67b40c41246c77f", + "message": "FIX test branch content\n", + "timestamp": 1577694074, + "time_from_now": "1天前" + }, + "author": { + "login": "18816895620", + "image_url": "avatars/User/b" + } + }, + { + "name": "master", + "user_can_push": true, + "user_can_merge": true, + "protected": false, + "http_url": "http://localhost:3003/18816895620/mirror_demo.git", + "zip_url": "http://localhost:3003/18816895620/mirror_demo/master.zip", + "tar_url": "http://localhost:3003/18816895620/mirror_demo/master.tar.gz", + "last_commit": { + "id": "19ac3bc45f62cc87a94b8ecce61101d8fd2dafd2", + "message": "合并pull request测试\n\n该功能很不错,感谢你的建议\n", + "timestamp": 1577244567, + "time_from_now": "6天前" + }, + "author": { + "login": "18816895620", + "image_url": "avatars/User/b" + } + } +] +``` +--- + +### 获取代码库标签列表 +``` +GET /api/repositories/:id/tags +``` +*示例* +``` +curl -X GET \ +-d "limit=20" \ +-d "page=1" \ +http://localhost:3000/api/repositories/5836/tags.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |仓库id | +|page |否|string |页数,第几页 | +|limit |否|string |每页多少条数据,默认20条 | + + +*返回参数说明:* + +|参数名|类型|说明| +-|-|- +|name |string|分支名称| +|user_can_push |boolean|用户是否可push| +|user_can_merge |boolean|用户是否客merge| +|protected |boolean|是否为保护分支| +|http_url |boolean|http链接| +|zip_url |boolean|zip包下载链接| +|tar_url |boolean|tar.gz下载链接| +|last_commit |object|最后提交记录| +|-- id |string|提交记录id| +|-- message |string|提交的说明信息| +|-- timestamp |int|提交时间,为UNIX时间戳| +|-- time_from_now|string|转换后的时间| +|author |object|提交用户| +|-- login |string|用户名称| +|-- image_url |string|用户头像| + + +返回值 +``` +[ + { + "name": "develop", + "user_can_push": true, + "user_can_merge": true, + "protected": false, + "http_url": "http://localhost:3003/18816895620/mirror_demo.git", + "zip_url": "http://localhost:3003/18816895620/mirror_demo/develop.zip", + "tar_url": "http://localhost:3003/18816895620/mirror_demo/develop.tar.gz", + "last_commit": { + "id": "735674d6696bddbafa993db9c67b40c41246c77f", + "message": "FIX test branch content\n", + "timestamp": 1577694074, + "time_from_now": "1天前" + }, + "author": { + "login": "18816895620", + "image_url": "avatars/User/b" + } + }, + { + "name": "master", + "user_can_push": true, + "user_can_merge": true, + "protected": false, + "http_url": "http://localhost:3003/18816895620/mirror_demo.git", + "zip_url": "http://localhost:3003/18816895620/mirror_demo/master.zip", + "tar_url": "http://localhost:3003/18816895620/mirror_demo/master.tar.gz", + "last_commit": { + "id": "19ac3bc45f62cc87a94b8ecce61101d8fd2dafd2", + "message": "合并pull request测试\n\n该功能很不错,感谢你的建议\n", + "timestamp": 1577244567, + "time_from_now": "6天前" + }, + "author": { + "login": "18816895620", + "image_url": "avatars/User/b" + } + } +] +``` +--- + +## 仓库详情 +``` +GET /api/:namespace_id/:project_id/repository +``` +*示例* +``` +curl -X GET \ +http://192.168.2.230:3000/api/jasder/forgeplus/repository | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|namespace_id |是|string |用户登录名 | +|project_id |是|string |项目标识identifier | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|identifier |string|仓库标识| +|project_id |int|项目id| +|project_identifier|string|项目标识| +|praises_count |int|点赞数量| +|forked_count |int|fork数量| +|watchers_count |int|关注数量| +|branches_count |int|分支数量| +|commits_count |int|总提交记录数量| +|issues_count |int|总提交记录数量| +|pull_requests_count |int|总提交记录数量| +|praised |boolean|当前登录用户是否已点赞,true:已点赞,fasle:未点赞, 用户未登录状态为null| +|watched |boolean|当前登录用户是否已关注,true:已关注,fasle:未关注, 用户未登录状态为null| +|permission |string|当前登录用户对该仓库的操作权限, Manager:管理员,可以在线编辑文件、在线新建文件、可以设置仓库的基本信息; Developer:开发人员,可在线编辑文件、在线新建文件、不能设置仓库信息; Reporter: 报告人员,只能查看信息,不能设置仓库信息、不能在线编辑文件、不能在线新建文件;用户未登录时也会返回Reporter, 说明也只有读取文件的权限 | +|size |int|仓库文件大小,单位:KB| +|type |int|项目类型; 2: 表示是一个镜像(具备同步功能), 1: 普通镜像项目(不具同步功能), 0: 普通托管项目, 3: fork项目| +|mirror_status |int|该字段在type字段为2(一个镜像)时才会出现; 0: 表示同步镜像成功;1: 表示正在同步镜像;2: 同步失败| +|mirror_url |string|镜像地址, 只有通过镜像过来的项目才会有这个地址| +|ssh_url |string|仓库ssh地址| +|clone_url |string|仓库克隆地址| +|empty |boolean|仓库是否为空,true: 空仓库;false: 非空仓库| +|private |boolean|仓库是否私有,true: 私有仓库;fasle: 非私有的| +|default_branch |string|仓库默认分支| +|full_name |string|仓库全名(带用户名)| +|author |object|提交用户| +|-- login |string|用户login| +|-- name |string|用户姓名| +|-- image_url |string|用户头像| + + +返回值 +``` +{ + "identifier": "mirror_demo", + "project_id": 3263, + "project_identifier": "mirror_demo", + "praises_count": 1, + "forked_count": 0, + "watchers_count": 1, + "branches_count": 6, + "commits_count": 107, + "issues_count": 0, + "pull_requests_count": 0, + "permission": "Manager", + "mirror_url": "https://gitea.com/CasperVector/slew.git", + "watched": true, + "praised": true, + "size": 446, + "ssh_url": "jasder@localhost:18816895620/mirror_demo.git", + "clone_url": "http://localhost:3003/18816895620/mirror_demo.git", + "default_branch": "master", + "empty": false, + "full_name": "18816895620/mirror_demo", + "mirror": false, + "private": false, + "author": { + "login": "18816895620", + "name": "美女", + "image_url": "avatars/User/b" + } +} +``` +--- + +## 获取提交记录列表 +``` +GET /api/repositories/:id/commits +``` +*示例* +``` +curl -X GET \ +-d "sha=develop" \ +-d "page=1" \ +http://localhost:3000/api/repositories/89/commits.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|sha |否|string |分支名称、提交记录的sha标识,默认为master分支 | +|page |否|int |页数, 默认为1 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count|int|总记录条数| +|commits |array|提交记录的数组| +|-- sha |string|提交记录sha标识| +|-- message |string|提交的备注说明| +|-- timestamp |int|提交UNIX时间戳| +|-- time_from_now|string|提交距离当前的时间| +|author |object|提交用户| +|-- login |string|用户名称| +|-- image_url |string|用户头像| + + +返回值 +``` +{ + "total_count": 63, + "commits": [ + { + "sha": "19ac3bc45f62cc87a94b8ecce61101d8fd2dafd2", + "message": "合并pull request测试", + "timestamp": 1577244567, + "time_from_now": "7天前", + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + } + }, + { + "sha": "2b33c5f55214db41879936312ee43611406c4dbd", + "message": "FIX .", + "timestamp": 1577244474, + "time_from_now": "7天前", + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + } + } + ] +} +``` +--- + +## 获取某个提交记录(包含diff) +``` +GET /api/:owner/:repo/commits/:sha +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/jasder/repo/commits/b0c4a4a1487d53acebf2addc544b29938cad12df.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |仓库拥有者 | +|repo |是|string |仓库的identifier值 | +|sha |否|string |git的ref或者是提交记录commit的sha标识 | + + +*返回参数说明: 请参考compare接口* + + +返回值 +``` +{ + "files_count": 6, + "total_addition": 447, + "total_deletion": 0, + "commit": { + "sha": "8f5faee0d3b3be1b8063e84da0c79dd75327b968", + "message": "add some file\n* Add the tag list page to the release page\n* Apply suggestions from code review\n* Add the tags list view\n* Add the delete tag way on ui\n* Not delete tag and clear message when delete a release\n", + "author": { + "name": "Jasder", + "email": "2053003901@@qq.com", + "date": "2020-11-03T13:56:22+08:00" + }, + "committer": { + "name": "Jasder", + "email": "2053003901@@qq.com", + "date": "2020-11-03T13:56:22+08:00" + }, + "timestamp": 1604382982, + "time_from_now": "3天前" + }, + "author": null, + "committer": null, + "parents": [ + { + "sha": "c7f5b90725f30d8ad840a026773f9df92debc3af" + }, + "files": [ + { + "name": "build.go", + "old_name": "build.go", + "index": 1, + "addition": 33, + "deletion": 0, + "type": 1, + "isCreated": true, + "isDeleted": false, + "isBin": false, + "isLFSFile": false, + "isRenamed": false, + "isSubmodule": false, + "sections": [ + { + "fileName": "build.go", + "name": "", + "lines": [ + { + "leftIdx": 0, + "rightIdx": 0, + "type": 4, + "content": "@@ -0,0 +1,33 @@", + "sectionInfo": { + "path": "build.go", + "lastLeftIdx": 0, + "lastRightIdx": 0, + "leftIdx": 0, + "rightIdx": 1, + "leftHunkSize": 0, + "rightHunkSize": 33 + } + }, + { + "leftIdx": 0, + "rightIdx": 1, + "type": 2, + "content": "+// Copyright 2020 The Gitea Authors. All rights reserved.", + "sectionInfo": null + } + ] + } + ] + } + ] +} +``` +--- + +### 点赞 +``` +POST /api/projects/:id/praise_tread/like +``` +*示例* +``` +curl -X POST http://localhost:3000/api/projects/3263/praise_tread/like | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是 |int |项目id | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:点赞成功,-1:操作失败,2:表示已经点过赞了| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +### 取消点赞 +``` +DELETE /api/projects/:id/praise_tread/unlike +``` +*示例* +``` +curl -X DELETE http://localhost:3000/api/projects/3263/praise_tread/unlike | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是 |int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:点赞成功,-1:操作失败,2:表示还未点赞| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +### 用户是否点过赞 +``` +GET /api/projects/:id/praise_tread/check_like +``` +*示例* +``` +curl -X GET http://localhost:3000/api/projects/3263/praise_tread/check_like | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是 |int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|1:已点过赞,0:未点过赞, -1:请求操作失败| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +### 项目的点赞者列表 +``` +GET /api/projects/:id/praise_tread +``` +*示例* +``` +curl -X GET \ +-d "page=1" \ +-d "limit=5" \ +http://localhost:3000/api/projects/3263/praise_tread | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|page |否|string |页数,第几页 | +|limit |否|string |每页多少条数据,默认15条 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int|总条数| +|praises |array|点赞数据| +|-- name |string|用户名称| +|-- login |string|用户标识/登录名(login)| +|-- image_url |string|用户头像| + + + +返回值 +``` +{ + "total_count": 1, + "praises": [ + { + "name": "18816895620", + "login": "18816895620", + "image_url": "avatars/User/b" + } + ] +} +``` +--- + +### 关注(项目) +``` +POST /api/projects/:id/watchers/follow +``` +*示例* +``` +curl -X POST http://localhost:3000/api/projects/3263/watchers/follow | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:点赞成功,-1:操作失败,2:表示已经点过赞了| + + +返回值 +``` +{ + "status": 0, + "message": "响应成功" +} +``` +--- + +### 取消关注 +``` +DELETE /api/projects/:id/watchers/unfollow +``` +*示例* +``` +curl -X DELETE http://localhost:3000//api/projects/3263/watchers/unfollow | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:点赞成功,-1:操作失败,2:表示还未点赞| + + +返回值 +``` +{ + "status": 0, + "message": "响应成功" +} +``` +--- + +### 用户是否关注过项目 +``` +GET /api/projects/:id/watchers/check_watch +``` +*示例* +``` +curl -X GET http://localhost:3000/api/projects/3263/watchers/check_watch | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是 |int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|1:已关注,0:未关注, -1:请求操作失败| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +### 项目的关注者列表 +``` +GET /api/projects/:id/watchers +``` +*示例* +``` +curl -X GET \ +-d "page=1" \ +-d "limit=5" \ +http://localhost:3000//api/projects/3263/watchers | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|page |否|string |页数,第几页 | +|limit |否|string |每页多少条数据,默认15条 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int|总条数| +|watchers |array|关注数据| +|-- name |string|用户名称| +|-- login |string|用户标识/登录名(login)| +|-- image_url |string|用户头像| + + +返回值 +``` +{ + "total_count": 1, + "watchers": [ + { + "name": "18816895620", + "login": "18816895620", + "image_url": "avatars/User/b" + } + ] +} +``` +--- + +### 仓库新建文件 +``` +POST /api/repositories/:id/create_file +``` +*示例* +``` +curl -X POST \ +-d 'filepath=test1_create_file1.rb' \ +-d 'branch=master' \ +-d 'content=提交的内容' \ +-d 'message=test commit ' \ +http://localhost:3000/api/18816895620/mirror_demo/contents.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|string |项目id | +|filepath |是|string |文件相对于仓库的路径 | +|content |否|string |内容 | +|message |否|string |提交说明 | +|branch |否|string |分支名称, branch和new_branch必须存在一个 | +|new_branch |否|string |新的分支名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|name |string|文件名| +|sha |string|提交文件的sha值| +|size |int|文件大小, 单位:B| +|content |string|base64编码后的文件内容| +|encoding |string|编码方式| +|commit |object|| +|-- message |string|提交备注说明信息| +|-- committer|object|| +|---- name |string|用户名| +|---- email |string|用户邮箱| +|---- date |string|文件创建时间| + + + +返回值 +``` +{ + "name": "test1_create_file12.rb", + "sha": "7b70509105b587e71f5692b9e8ab70851e321f64", + "size": 12, + "content": "Wm5ObWMyRmtaZz09", + "encoding": "base64", + "commit": { + "message": "good luck\n", + "author": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-07T03:31:20Z" + }, + "committer": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-07T03:31:20Z" + } + } +} +``` +--- + +### 更新仓库中的文件 +``` +PUT /api/repositories/:id/update_file.json +``` +*示例* +``` +curl -X PUT \ +-d 'filepath=text1.rb' \ +-d 'branch=master' \ +-d 'content=ruby code' \ +-d 'message=更改提交信息' \ +-d 'from_path=text.rb' \ +-d "sha=57426eb21e4ceabdf4b206f022077e0040" \ +http://localhost:3000/api/repositories/3938/update_file.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|filepath |是|string |文件相对于仓库的路径(或修改后的文件路径) | +|from_path |是|string |原文件相对于仓库的路径, 只有当需要修改原文件名称时,才需要该参数 | +|sha |是|string |文件的sha标识值 | +|content |是|string |内容 | +|message |否|string |提交说明 | +|branch |否|string |分支名称, branch和new_branch必须存在一个,且只能存在一个 | +|new_branch |否|string |新的分支名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|name |string|文件名| +|sha |string|提交文件的sha值| +|size |int|文件大小, 单位:B| +|content |string|base64编码后的文件内容| +|encoding |string|编码方式| +|commit |object|| +|-- message |string|提交备注说明信息| +|-- committer|object|| +|---- name |string|用户名| +|---- email |string|用户邮箱| +|---- date |string|文件创建时间| + + +返回值 +``` +{ + "name": "test1_create_file6.rb", + "sha": "57426eb21e4ceabdf4b206f022257e08077e0040", + "size": 16, + "content": "5o+Q5Lqk55qE5YaF5a65MQ==", + "encoding": "base64", + "commit": { + "message": "更改提交信息\n", + "author": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-08T07:05:15Z" + }, + "committer": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-08T07:05:15Z" + } + } +} +``` +--- + +### 删除仓库中的文件 +``` +DELETE /api/repositories/:id/delete_file +``` +*示例* +``` +curl -X DELETE \ +-d 'filepath=test1_create_file12.rb' \ +-d 'test delete file' \ +-d 'sha=7b70509105b587e71f5692b9e8ab70851e321f64' \ +http://localhost:3000/api//api/repositories/3868/delete_file | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|filepath |是|string |文件相对于仓库的路径 | +|message |否|string |提交说明 | +|branch |否|string |分支名称, 默认为master分支| +|new_branch |否|string |新的分支名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|sha |string|提交文件的sha值| +|commit |object|| +|-- message |string|提交备注说明信息| +|-- committer|object|| +|---- name |string|用户名| +|---- email |string|用户邮箱| +|---- date |string|文件创建时间| + + +返回值 +```json +{ + "commit": { + "sha": "7b70509105b587e71f5692b9e8ab70851e321f64", + "message": "Delete 'test1_create_file11.rb'\n", + "author": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-08T07:57:34Z"`` + }, + "committer": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-08T07:57:34Z" + } + } +} +``` +--- + +### 获取pull request文件列表 +``` +GET /api/:owner/:repo/pulls/:id/files.json +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/Jason/test-txt/pulls/1/files.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | +|id |是|int |pull request's id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|files_count |int|文件更改的总数量| +|total_addition |int|添加代码总行数| +|total_deletion |int|删除代码总行数| +|files |array|| +|-- sha |string|commit's sha value| +|-- name |string|当前文件名| +|-- old_name |string| 修改之前的文件名称,与name相同的话,说明文件名未更改| +|-- addition |int|文件添加的行数| +|-- deletion |int|文件删除的行数| +|-- type |int|文件类型, 1: 表示该文件只添加了内容,2: 表示该文件内容有修改, 3: 表示文件被删除或者改文件只删除了内容| +|-- isCreated |boolean|当前文件是否为新增文件, true: 是, false: 否| +|-- isDeleted |boolean|当前文件是否被删除, true: 是,false: 否| +|-- isBin |boolean|当前文件是否为二进制文件,true: 是,false: 否| +|-- isLFSFile |boolean|当前文件是否为LFS文件,true: 是,false: 否| +|-- isRenamed |boolean|当前文件是否被重命名,true: 是,false: 否| +|-- sections |array|| +|---- fileName |string|文件名称| +|---- lines |array|| +|------ leftIdx |string|文件变动之前所在行数| +|------ rightIdx |string|文件更改后所在行数| +|------ type |string|文件变更类型,1: 新增,2: 修改, 3: 删除, 4: diff统计信息| +|------ content |string|文件变更的内容| +|------ sectionInfo |object|| +|-------- path |string|文件相对仓库的路径| +|-------- lastLeftIdx |int|| +|-------- lastRightIdx |int|| +|-------- leftHunkSize |int|文件变更之前的行数| +|-------- rightHunkSize |int|文件变更之后的行数(及当前页面编辑器显示的总行数)| +|-------- leftIdx |int|文件变更之前所在行数| +|-------- rightIdx |int|文件变更之后所在行数(即:页面编辑器开始显示的行数)| + + +返回值 +```json +{ + "files_count": 6, + "total_addition": 447, + "total_deletion": 0, + "files": [ + { + "sha": "xefenisnii", + "name": "文件.txt", + "old_name": "文件.txt", + "index": 6, + "addition": 2, + "deletion": 0, + "type": 1, + "isCreated": true, + "isDeleted": false, + "isBin": false, + "isLFSFile": false, + "isRenamed": false, + "isSubmodule": false, + "sections": [ + { + "fileName": "文件.txt", + "name": "", + "lines": [ + { + "leftIdx": 0, + "rightIdx": 0, + "type": 4, + "content": "@@ -0,0 +1,2 @@", + "sectionInfo": { + "path": null, + "lastLeftIdx": null, + "lastRightIdx": null, + "leftIdx": 0, + "rightIdx": 0, + "leftHunkSize": null, + "rightHunkSize": null + } + }, + { + "leftIdx": 0, + "rightIdx": 1, + "type": 2, + "content": "+用例图一致性更新", + "sectionInfo": null + }, + { + "leftIdx": 0, + "rightIdx": 2, + "type": 2, + "content": "+工程文件直接上传会有文件缺失,现在压缩后上传", + "sectionInfo": null + } + ] + } + ] + } + ] +} +``` +--- + +### 获取pull request的commits列表 +``` +GET /api/:owner/:repo/pulls/:id/commits.json +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/Jason/repo/1/commits.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | +|id |是|int |pull request's id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|commits_count |int|commits总数量| +|commits |array|| +|-- author |object|项目作者| +|---- login |string|用户login| +|---- name |string|用户姓名| +|---- image_url |string|用户头像| +|-- committer |object|commit提交用户| +|---- login |string|用户login| +|---- name |string|用户姓名| +|---- image_url |string|用户头像| +|-- timestamp |int|commit的unix时间戳| +|-- time_from_now|string|commit’s 提交时间距当前时间的时间值| +|-- message |string|commit说明信息| +|-- sha |string|commit’s sha值| + +返回值 +```json +{ + "commits_count": 1, + "commits": [ + { + "author": { + "id": 36480, + "login": "jasder", + "name": "段甲生", + "image_url": "avatars/User/b" + }, + "committer": { + "id": 36480, + "login": "jasder", + "name": "段甲生", + "image_url": "avatars/User/b" + }, + "timestamp": 1604382982, + "time_from_now": "3小时前", + "message": "add some file\n* Add the tag list page to the release page\n* Apply suggestions from code review\n* Add the tags list view\n* Add the delete tag way on ui\n* Not delete tag and clear message when delete a release\n", + "sha": "8f5faee0d3b3be1b8063e84da0c79dd75327b968" + } + ] +} +``` +--- + +### compare two commits +``` +GET /api/:owner/:repo/compare/{base}...{head}.json +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/Jason/test-txt/compare/master...develop | jq + +curl -X GET \ +http://localhost:3000/api/ysfns/test-txt/compare/master...Jason/test-txt:develop +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | +|base |是|string |pull request's id | +|head |是|string |pull request's id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|commits_count |int|commits总数量| +|commits |array|| +|-- author |object|项目作者| +|---- login |string|用户login| +|---- name |string|用户姓名| +|---- image_url |string|用户头像| +|-- committer |object|commit提交用户| +|---- login |string|用户login| +|---- name |string|用户姓名| +|---- image_url |string|用户头像| +|-- timestamp |int|commit的unix时间戳| +|-- time_from_now|string|commit’s 提交时间距当前时间的时间值| +|-- message |string|commit说明信息| +|-- sha |string|commit’s sha值| +|diff |object|| +|-- files_count |int|文件更改的总数量| +|-- total_addition |int|添加代码总行数| +|-- total_deletion |int|删除代码总行数| +|-- files |Array|| +|-- sha |string|commit's sha | +|-- name |string|当前文件名| +|-- old_name |string| 修改之前的文件名称,与name相同的话,说明文件名未更改| +|-- addition |int|文件添加的行数| +|-- deletion |int|文件删除的行数| +|-- type |int|文件类型, 1: 表示该文件只添加了内容,2: 表示该文件内容有修改, 3: 表示文件被删除或者改文件只删除了内容| +|-- isCreated |boolean|当前文件是否为新增文件, true: 是, false: 否| +|-- isDeleted |boolean|当前文件是否被删除, true: 是,false: 否| +|-- isBin |boolean|当前文件是否为二进制文件,true: 是,false: 否| +|-- isLFSFile |boolean|当前文件是否为LFS文件,true: 是,false: 否| +|-- isRenamed |boolean|当前文件是否被重命名,true: 是,false: 否| +|-- sections |array|| +|---- fileName |string|文件名称| +|---- lines |array|| +|------ leftIdx |string|文件变动之前所在行数| +|------ rightIdx |string|文件更改后所在行数| +|------ type |string|文件变更类型,1: 内容未改动,2: 添加, 3: 删除, 4: diff统计信息| +|------ content |string|文件变更的内容| +|------ sectionInfo |object|| +|-------- path |string|文件相对仓库的路径| +|-------- lastLeftIdx |int|| +|-------- lastRightIdx |int|| +|-------- leftHunkSize |int|文件变更之前的行数| +|-------- rightHunkSize |int|文件变更之后的行数(及当前页面编辑器显示的总行数)| +|-------- leftIdx |int|文件变更之前所在行数| +|-------- rightIdx |int|文件变更之后所在行数| + +返回值 +```json +{ + "commits_count": 1, + "commits": [ + { + "author": { + "id": 36480, + "login": "jasder", + "name": "段甲生", + "image_url": "avatars/User/b" + }, + "committer": { + "id": 36480, + "login": "jasder", + "name": "段甲生", + "image_url": "avatars/User/b" + }, + "timestamp": 1604382982, + "time_from_now": "4小时前", + "message": "add some file\n* Add the tag list page to the release page\n* Apply suggestions from code review\n* Add the tags list view\n* Add the delete tag way on ui\n* Not delete tag and clear message when delete a release\n", + "sha": "8f5faee0d3b3be1b8063e84da0c79dd75327b968" + } + ], + "diff": { + "files_count": 6, + "total_addition": 447, + "total_deletion": 0, + "files": [ + { + "name": "build.go", + "old_name": "build.go", + "index": 1, + "addition": 33, + "deletion": 0, + "type": 1, + "isCreated": true, + "isDeleted": false, + "isBin": false, + "isLFSFile": false, + "isRenamed": false, + "isSubmodule": false, + "sections": [ + { + "fileName": "build.go", + "name": "", + "lines": [ + { + "leftIdx": 0, + "rightIdx": 0, + "type": 4, + "content": "@@ -0,0 +1,33 @@", + "sectionInfo": { + "path": "build.go", + "lastLeftIdx": 0, + "lastRightIdx": 0, + "leftIdx": 0, + "rightIdx": 1, + "leftHunkSize": 0, + "rightHunkSize": 33 + } + }, + { + "leftIdx": 0, + "rightIdx": 1, + "type": 2, + "content": "+// Copyright 2020 The Gitea Authors. All rights reserved.", + "sectionInfo": null + } + ] + } + ] + } + ] + } +} +``` +--- + + +### DevOps相关api +--- + +#### 获取devops流程步骤 +``` +GET /api/:owner/:repo/ci_authorize +``` + +*示例* +``` +curl -X GET \ +http://localhost:3000/api/jasder/forgeplus/ci_authorize.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|step |int|初始化devops流程步骤; 0: 标识未开启devops,1: 标识用户已填写了云服务器相关信息,但并未开启认证, 2: 标识用户已开启了CI服务端的认证| +|account |string|你的云服务器帐号| +|ip |string|你的云服务器帐号ip| +|secret |string|你的云服务器登录密码| +|authenticate_url |string|devops授权认证地址, 只有填写了服务器相关信息后才会有该地址| +|get_drone_token_url |string|获取CI服务端token地址, 只有认证成功后才会有该地址| + +返回值 +```json +{ + "step": 0, + "cloud_account": { + "id": 1, + "account": "xxx", + "ip": "xxx.xxx.xxx.x", + "secret": "11111", + "authenticate_url": "http://localhost:3000/login", + "get_drone_token_url": "http://localhost:3000/account" + } +} +``` +--- + +#### 初始化DevOps流程 +``` +POST /api/:owner/:repo/cloud_accounts +``` + +*示例* +``` +curl -X POST \ +-d "account=xx" \ +-d "secret=xxx" \ +-d "ip_num=xx.xx.xx.xx" \ +https://localhost:3000/api/jasder/forgeplus/cloud_accounts.json | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | +|account |是|string |云服务器ssh连接登录用户名 | +|secret |是|string |云服务器ssh连接登录秘密 | +|ip_num |否|string |云服务器公网IP | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |string|服务端返回状态,0: 表示请求成功, -1: 标识请求失败| +|message |string|服务端返回信息说明| +|redirect_url |string|重定向地址,请求成功后,需要调整到该地址进行认证| + +返回值 +```json +{ + "status": 0, + "message": "success", + "redirect_url": "http://192.168.2.59:3003/login/oauth/authorize?client_id=f0c58484-d0f7-46c0-9efd-de3e3218e723&redirect_uri=http://121.36.81.172:80/login&response_type=code" +} +``` +--- + +#### devops用户认证授权 +``` +GET /api/users/ci/oauth_grant +``` +*示例* +``` +curl -X GET \ +-d "password=123456" \ +http://localhost:3000/api/users/ci/oauth_grant.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|password |是|string |用户密码 | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:成功, -1: 失败| + +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +#### 激活项目 +``` +POST /api/:owner/:repo/activate +``` +*示例* +``` +curl -X POST \ +http://localhost:3000/api/jasder/forgeplus/activate.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:成功, -1: 失败| + +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +#### 取消激活项目 +``` +DELETE /api/:owner/:repo/deactivate +``` +*示例* +``` +curl -X POST \ +http://localhost:3000/api/jasder/forgeplus/deactivate.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:成功, -1: 失败| + +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +#### 获取仓库的.trustie-pipeline.yml +``` +GET /api/:owner/:repo/get_trustie_pipeline +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/jasder/forge/get_trustie_pipeline.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | +|ref |否|string |分支名称、tag名称或是提交记录id,默认为master分支 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|name |string|文件夹或文件名称| +|path |string|文件夹或文件相对路径| +|content |string|文件内容,| + +``` +{ + "name": ".trustie-pipeline.yml", + "path": ".trustie-pipeline.yml", + "sha": "548sfefsafef48sf485s4f", + "content": "..jsaf" +} +``` +--- + +#### 更新'.trustie-pipeline.yml'文件 +``` +PUT /api/:owner/:repo/update_trustie_pipeline +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/jasder/forge/update_trustie_pipeline.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |用户登录名 | +|repo |是|string |project's identifier | +|ref |否|string |分支名称、tag名称或是提交记录id,默认为master分支 | +|filepath |是|string |文件相对于仓库的路径(或修改后的文件路径) | +|from_path |是|string |原文件相对于仓库的路径, 只有当需要修改原文件名称时,才需要该参数 | +|sha |是|string |文件的sha标识值 | +|content |是|string |内容 | +|message |否|string |提交说明 | +|branch |否|string |分支名称, branch和new_branch必须存在一个,且只能存在一个 | +|new_branch |否|string |新的分支名称 | +|ci_language_id |否|string |新的分支名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|接口返回状态, 1: 请求成功, -1: 请求失败| +|message |string|文件夹或文件相对路径| + +``` +{ + "status": 1, + "message": ".trustie-pipeline.yml" +} +``` +--- + +#### 获取语言列表 +``` +GET /api/ci/languages +``` + +*示例* +``` +curl -X GET http://localhost:3000/api/ci/languages.json | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int|id值| +|name |string|语言名称| +|content |string|语言内容| +|cover_url |string|语言的logo链接| + +返回值 +```json +[ + { + "id": 114, + "name": "C", + "cover_url": null, + "content": "kind: pipeline\n name: default\n\n platform:\n os: linux\n arch: arm64\n\n steps:\n - name: test\n image: gcc\n commands:\n - ./configure\n - make\n - make test", + } +] +``` +--- + +#### 获取常用的6大语言 +``` +GET /api/ci/languages/common +``` + +*示例* +``` +curl -X GET http://localhost:3000/api/ci/languages/common.json | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int|id值| +|name |string|语言名称| +|content |string|语言内容| +|cover_url |string|语言的logo链接| + +返回值 +```json +[ + { + "id": 114, + "name": "C", + "cover_url": null, + "content": "kind: pipeline\n name: default\n\n platform:\n os: linux\n arch: arm64\n\n steps:\n - name: test\n image: gcc\n commands:\n - ./configure\n - make\n - make test", + } +] +``` +--- + +#### 获取语言详情 +``` +GET /api/ci/languages/:id +``` + +*示例* +``` +curl -X GET http://localhost:3000/api/ci/languages/114.json | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |language's id | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int|id值| +|name |string|语言名称| +|content |string|语言内容| +|cover_url |string|语言的logo链接| + +返回值 +```json +[ + { + "id": 114, + "name": "C", + "cover_url": null, + "content": "kind: pipeline\n name: default\n\n platform:\n os: linux\n arch: arm64\n\n steps:\n - name: test\n image: gcc\n commands:\n - ./configure\n - make\n - make test", + } +] +``` +--- + +#### 获取构建列表 +``` +GET /api/:owner/:repo/builds +``` + +*示例* +``` +curl -X GET \ +http://localhost:3000/api/Jason/forge/builds | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|owner |是|string |项目拥有者 | +|repo |是|string |项目identifier | +|page |否|string |页数,第几页 | +|limit |否|string |每页多少条数据,默认20条 | +|search |是|string |构建状态条件过滤; 值说明:pending: 准备中,failure: 构建失败,running: 运行中,error:构建失败(.trustie-pipeline.yml文件错误),success: 构建成功,killed: 撤销构建 | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int|build's id| +|number |string|build's number| +|status |string|build's result| +|event |string|build's event| + +返回值 +```json +[ + { + "id": 1, + "repo_id": 8, + "trigger": "@hook", + "number": 1, + "status": "success", + "event": "push", + "action": "", + "link": "", + "timestamp": 0, + "message": "更新 '.trustie-pipeline.yml'\n", + "before": "5e7c6f7dfd5ce6cc6e287fcbc000dadd9992b324", + "after": "5e52ce51a239f5c8dd0b489a8a71e94f976179b4", + "ref": "refs/heads/master", + "source_repo": "", + "source": "master", + "target": "master", + "author_login": "jasder", + "author_name": "jasder", + "author_email": "email.com", + "author_avatar": "", + "sender": "jasder", + "started": "2020-08-19 06:22", + "finished": "2020-08-19 06:22", + "created": "2020-08-19 06:22", + "updated": "2020-08-19 06:22", + "duration_time": 0, + "version": 3 + } +] +``` +--- + +#### 获取某条构建详情信息 +``` +GET /api/:owner/:repo/builds/:build +``` + +*示例* +``` +curl -X GET \ +http://ocalhost:3000/api/jasder/forge/builds/1 | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|build |是|int |build's number | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int|build's id| +|status |string|build's status| +|event |string|build's event| + +返回值 +```json +{ + "id": 1, + "repo_id": 8, + "trigger": "@hook", + "number": 1, + "status": "success", + "event": "push", + "action": "", + "link": "http://localhost:3000/jasder/forgeplus/compare/5e7c6f7dfd5ce6cc6e287fcbc000dadd9992b324...5e52ce51a239f5c8dd0b489a8a71e94f976179b4", + "timestamp": 0, + "message": "更新 '.trustie-pipeline.yml'\n", + "before": "5e7c6f7dfd5ce6cc6e287fcbc000dadd9992b324", + "after": "5e52ce51a239f5c8dd0b489a8a71e94f976179b4", + "ref": "refs/heads/master", + "source_repo": "", + "source": "master", + "target": "master", + "author_login": "jasder", + "author_name": "jasder", + "author_email": "2053003901@qq.com", + "author_avatar": "http://localhost:3000/user/avatar/jasder/-1", + "sender": "jasder", + "started": 1595317786, + "finished": 1595318426, + "created": 1595317786, + "updated": 1595317786, + "version": 3, + "stages": [ + { + "id": 1, + "repo_id": 8, + "build_id": 1, + "number": 1, + "name": "default", + "kind": "pipeline", + "type": "docker", + "status": "success", + "errignore": false, + "exit_code": 0, + "machine": "121.36.81.172", + "os": "linux", + "arch": "arm64", + "started": 1595317786, + "stopped": 1595318426, + "created": 1595317786, + "updated": 1595318426, + "version": 4, + "on_success": true, + "on_failure": false, + "steps": [ + { + "id": 1, + "step_id": 1, + "number": 1, + "name": "clone", + "status": "success", + "exit_code": 0, + "started": 1595317786, + "stopped": 1595318373, + "version": 4 + }, + { + "id": 2, + "step_id": 1, + "number": 2, + "name": "test", + "status": "success", + "exit_code": 0, + "started": 1595318373, + "stopped": 1595318426, + "version": 4 + } + ] + } + ] +} +``` +--- + +#### 重启构建/重新构建 +``` +POST /api/:owner/:repo/builds/:build/restart +``` + +*示例* +``` +curl -X POST \ +http://localhost:3000/api/jasder/forgeplus/builds/1 | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|build |是|int |build's number | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int|build's id| +|status |string|build's status| +|event |string|build's event| + +返回值 +```json +{ + "id": 2, + "repo_id": 8, + "trigger": "jasder", + "number": 2, + "status": "pending", + "event": "push", + "action": "", + "link": "http://localhost:3000/jasder/forgeplus/compare/5e7c6f7dfd5ce6cc6e287fcbc000dadd9992b324...5e52ce51a239f5c8dd0b489a8a71e94f976179b4", + "timestamp": 0, + "message": "更新 '.trustie-pipeline.yml'\n", + "before": "5e7c6f7dfd5ce6cc6e287fcbc000dadd9992b324", + "after": "5e52ce51a239f5c8dd0b489a8a71e94f976179b4", + "ref": "refs/heads/master", + "source_repo": "", + "source": "master", + "target": "master", + "author_login": "jasder", + "author_name": "jasder", + "author_email": "2053003901@qq.com", + "author_avatar": "http://localhost:3000/user/avatar/jasder/-1", + "sender": "jasder", + "started": 0, + "finished": 0, + "created": 1595321350, + "updated": 1595321350, + "version": 1 +} +``` +--- + +#### 关闭构建 +``` +DELETE /api/:owner/:repo/builds/:build/stop +``` + +*示例* +``` +curl -X DELETE \ +http://localhost:3000/api/jaser/forge/builds/2 | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|build |是|int |build's number | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int|build's id| +|status |string|build's status| +|event |string|build's event| + +返回值 +```json +{ + "id": 2, + "repo_id": 8, + "trigger": "jasder", + "number": 2, + "status": "killed", + "event": "push", + "action": "", + "link": "http://localhost:3000/jasder/forgeplus/compare/5e7c6f7dfd5ce6cc6e287fcbc000dadd9992b324...5e52ce51a239f5c8dd0b489a8a71e94f976179b4", + "timestamp": 0, + "message": "更新 '.trustie-pipeline.yml'\n", + "before": "5e7c6f7dfd5ce6cc6e287fcbc000dadd9992b324", + "after": "5e52ce51a239f5c8dd0b489a8a71e94f976179b4", + "ref": "refs/heads/master", + "source_repo": "", + "source": "master", + "target": "master", + "author_login": "jasder", + "author_name": "jasder", + "author_email": "2053003901@qq.com", + "author_avatar": "http://localhost:3000/user/avatar/jasder/-1", + "sender": "jasder", + "started": 1595321352, + "finished": 1595321590, + "created": 1595321350, + "updated": 1595321352, + "version": 3, + "stages": [ + { + "id": 2, + "repo_id": 8, + "build_id": 2, + "number": 1, + "name": "default", + "kind": "pipeline", + "type": "docker", + "status": "killed", + "errignore": false, + "exit_code": 0, + "machine": "121.36.81.172", + "os": "linux", + "arch": "arm64", + "started": 1595321352, + "stopped": 1595321590, + "created": 1595321350, + "updated": 1595321352, + "version": 4, + "on_success": true, + "on_failure": false, + "steps": [ + { + "id": 3, + "step_id": 2, + "number": 1, + "name": "clone", + "status": "killed", + "exit_code": 130, + "started": 1595321353, + "stopped": 1595321590, + "version": 3 + }, + { + "id": 4, + "step_id": 2, + "number": 2, + "name": "test", + "status": "skipped", + "exit_code": 130, + "started": 1595321590, + "stopped": 1595321590, + "version": 2 + } + ] + } + ] +} +``` +--- + +#### 获取某条构建的log信息 +``` +GET /api/:owner/:repo/builds/:build/logs/:stage/:step +``` + +*示例* +``` +curl -X GET \ +http://localhost:3000/api/dev_ops/builds/2/logs/1/1 | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|build |是|int |build's number | +|stage |是|int |build's stage number | +|step |是|int |build's step number | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int|build's id| +|status |string|build's status| +|event |string|build's event| + +返回值 +```json +[ + { + "pos": 0, + "out": "+ git fetch origin +refs/heads/master:\n", + "time": 1 + }, + { + "pos": 1, + "out": "Initialized empty Git repository in /drone/src/.git/\n", + "time": 1 + }, + { + "pos": 2, + "out": "warning: redirecting to https://testgitea2.trustie.net/jasder/forgeplus.git/\n", + "time": 1 + }, + { + "pos": 3, + "out": "From http://testgitea2.trustie.net/jasder/forgeplus\n", + "time": 493 + }, + { + "pos": 4, + "out": " * branch master -> FETCH_HEAD\n", + "time": 493 + }, + { + "pos": 5, + "out": " * [new branch] master -> origin/master\n", + "time": 493 + }, + { + "pos": 6, + "out": "+ git checkout 5e52ce51a239f5c8dd0b489a8a71e94f976179b4 -b master\n", + "time": 493 + }, + { + "pos": 7, + "out": "Already on 'master'\n", + "time": 496 + } +] +``` +--- + +#### 获取CI服务器配置信息 +``` +GET /api/users/ci/cloud_account +``` + +*示例* +``` +curl -X GET \ +http://localhost:3000/api/users/ci/cloud_account | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|step |int|0: 未绑定;1: 未认证(已绑定)| +|ci_certification |boolean|true: 已认证, false: 未认证| +|ip |string|ci服务器ip| +|redirect_url |string|认证地址| + +返回值 +```json +{ + "step": 0, + "ci_certification": false, + "cloud_account": { + "ip": "xxx.xxx.xxx.x", + "redirect_url": "http://localhost:3000/login", + } +} +``` +--- + +#### 绑定CI服务器 +``` +POST /api/users/ci/cloud_account/bind +``` + +*示例* +``` +curl -X POST \ +-d "account=xx" \ +-d "secret=xxx" \ +-d "ip_num=xx.xx.xx.xx" \ +https://localhost:3000/api/users/ci/cloud_account/bind.json | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|account |是|string |云服务器ssh连接登录用户名 | +|secret |是|string |云服务器ssh连接登录秘密 | +|ip_num |否|string |云服务器公网IP | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|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服务器绑定 +``` +DELETE /api/users/ci/cloud_account/unbind +``` + +*示例* +``` +curl -X DELETE \ +http://localhost:3000/api/users/ci/cloud_account/unbind.json | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|状态码, 0: 成功,-1: 失败| +|message |string|返回信息说明| + +返回值 +```json +{ + "status": 0, + "message": "success" +} +``` +--- + +### 项目列表 +``` +GET /api/users/:login/projects +``` + +*示例* +``` +curl -X GET \ +-d "page=1" \ +-d "limit=20" \ +http://localhost:3000/api/users/Jason/projects.json | jq +``` + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|page |否|int |页数,第几页 | +|limit |否|int |每页多少条数据,默认20条 | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int |项目总条数 | +|id |string |项目id | +|name |string|项目名称| +|description |string|项目简介| +|open_devops |boolean|激活状态,true: 激活; false:未激活| +|visits |int|流量数| +|forked_count |int|被fork的数量| +|praises_count |int|star数量| +|is_public |boolean|是否公开, true:公开,false:未公开| +|mirror_url |string|镜像url| +|last_update_time|int|最后更新时间,为UNIX格式的时间戳| +|author |object|项目创建者| +|-- name |string|用户名,也是用户标识| +|category |object|项目类别| +|-- id |int|项目类型id| +|-- name |string|项目类型名称| +|language |object|项目语言| +|-- id |int|项目语言id| +|-- name |string|项目语言名称| + + +返回值 +``` +{ + "total_count": 3096, + "projects": [ + { + "id": 1, + "name": "hnfl_demo1", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": null, + "last_update_time": 1577697461, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + } + ] +} +``` +--- diff --git a/app/assets/stylesheets/oauth.scss b/app/assets/stylesheets/oauth.scss new file mode 100644 index 00000000..e862b52d --- /dev/null +++ b/app/assets/stylesheets/oauth.scss @@ -0,0 +1,78 @@ +html{margin:0px;padding: 0px;font-size: 14px;font-family: "微软雅黑","宋体";} +body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { + margin: 0; + padding: 0; +} +.IndexContent{ + height: 100vh; + width: 100%; + position: relative; + background-image: url('/images/oauth/backImg.png'); + background-repeat: no-repeat; + background-size: cover; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; +} +.indexLogo{ + width:80px; + margin-bottom: 35px; +} +.indexPanel{ + width: 580px; + min-height: 400px; + background-color: #fff; + box-shadow: 0px 2px 10px 5px rgba(0,0,0,0.05); + border-radius: 5px; + box-sizing: border-box; +} +.indexTitle{ + height: 75px; + line-height: 75px; + font-size: 18px; + color:#333; + text-align: center; + border-bottom: 1px solid #eee; +} +.indexInfo{ + display: flex; + flex-direction: column; + align-items: flex-start; +} +.indexInfos{ + padding:40px 60px; +} +.indexInfo > span{ + color: #333; + font-size: 16px; + margin-top: 5px; +} +.indexInfo input{ + width: 100%; + height:40px; + border-radius: 2px; + border:1px solid #eee; + margin-top: 5px; + padding:0px 0px 0px 8px; + outline: none; +} +.indexInfo .checkInfo{ + height: 15px; + color: red; +} +.indexBtn{ + text-align: center; + margin-top: 20px; +} +.indexSubmit{ + width: 50%; + height: 32px; + line-height: 32px; + background-color: #1890FF; + border:none; + color: #fff; + border-radius: 2px; + cursor: pointer; + outline: none; +} diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 5731b321..7b1ac04d 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -9,8 +9,9 @@ module ApplicationCable private def find_verified_user - puts "############### cookies.signed[:signed_user_id]: #{cookies.signed[:user_id]}" + puts "############### cookies.signed[:user_id]: #{cookies.signed[:user_id]}" if current_user = User.find_by(id: cookies.signed[:user_id]) + puts "############### find_verified_user success! ###############" current_user else reject_unauthorized_connection diff --git a/app/channels/mirror_project_channel.rb b/app/channels/mirror_project_channel.rb index 62d51dad..fa344db5 100644 --- a/app/channels/mirror_project_channel.rb +++ b/app/channels/mirror_project_channel.rb @@ -1,7 +1,6 @@ class MirrorProjectChannel < ApplicationCable::Channel def subscribed Rails.logger.info "################### channel params: #{params}" - # @project = Project.find_by_identifier params[:id] stream_from "channel_room_#{params[:id]}" end diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index b06dab70..afa35a6a 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -13,25 +13,12 @@ class AccountsController < ApplicationController password = params[:password] platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") - @user = User.new(admin: false, login: username, mail: email, type: "User") - @user.password = password - @user.platform = platform - @user.activate - ActiveRecord::Base.transaction do - interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) - if interactor.success? - gitea_user = interactor.result - result = Gitea::User::GenerateTokenService.new(username, password).call - @user.gitea_token = result['sha1'] - @user.gitea_uid = gitea_user['id'] - if @user.save! - UserExtension.create!(user_id: @user.id) - @user.create_wallet(balance: 0) - render_ok({user: {id: @user.id, token: @user.gitea_token}}) - end + result = autologin_register(username, email, password, platform) + if result[:message].blank? + render_ok({user: result[:user]}) else - render_error(interactor.error) + render_error(result[:message]) end end rescue Exception => e @@ -67,8 +54,8 @@ class AccountsController < ApplicationController sync_params = {} - if (user_params["mail"] && user_params["mail"] != user_mail) || (user_params["login"] && user_params["login"] != params[:old_user_login]) - sync_params = sync_params.merge(email: user_params["mail"], login_name: user_params["login"], full_name: user_params["login"]) + if (user_params["mail"] && user_params["mail"] != user_mail) + sync_params = sync_params.merge(email: user_params["mail"]) end if sync_params.present? @@ -123,33 +110,33 @@ class AccountsController < ApplicationController # params[:login] 邮箱或者手机号 # params[:code] 验证码 # code_type 1:注册手机验证码 8:邮箱注册验证码 + # 本地forge注册入口 def register begin # 查询验证码是否正确;type只可能是1或者8 type = phone_mail_type(params[:login].strip) - code = params[:code].strip + # code = params[:code].strip if type == 1 uid_logger("start register by phone: type is #{type}") pre = 'p' email = nil phone = params[:login] - verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last + # verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last + # TODO: 暂时限定邮箱注册 + return normal_status(-1, '只支持邮箱注册') else uid_logger("start register by email: type is #{type}") pre = 'm' email = params[:login] phone = nil - verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last + return normal_status(-1, "该邮箱已注册") if User.exists?(mail: params[:login]) + return normal_status(-1, "邮箱格式错误") unless params[:login] =~ CustomRegexp::EMAIL + # verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last end - uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}") + # uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}") # check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60) # todo 上线前请删除万能验证码"513231" - unless code == "513231" && request.subdomain == "test-newweb" - return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip - return normal_status(-2, "验证码已失效") if !verifi_code&.effective? - end - return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:password] =~ CustomRegexp::PASSWORD code = generate_identifier User, 8, pre @@ -159,23 +146,20 @@ class AccountsController < ApplicationController # 现在因为是验证码,所以在注册的时候就可以激活 @user.activate # 必须要用save操作,密码的保存是在users中 - if @user.save! - # todo user_extension - UserExtension.create!(user_id: @user.id) - # 注册完成,手机号或邮箱想可以奖励500金币 - # RewardGradeService.call( - # @user, - # container_id: @user.id, - # container_type: pre == 'p' ? 'Phone' : 'Mail', - # score: 500 - # ) - # 注册时,记录是否是引流用户 - ip = request.remote_ip - ua = UserAgent.find_by_ip(ip) - ua.update_column(:agent_type, UserAgent::USER_REGISTER) if ua - successful_authentication(@user) - # session[:user_id] = @user.id - normal_status("注册成功") + + interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: params[:password]}) + if interactor.success? + gitea_user = interactor.result + result = Gitea::User::GenerateTokenService.new(login, params[:password]).call + @user.gitea_token = result['sha1'] + @user.gitea_uid = gitea_user['id'] + if @user.save! + UserExtension.create!(user_id: @user.id) + successful_authentication(@user) + normal_status("注册成功") + end + else + tip_exception(-1, interactor.error) end rescue Exception => e uid_logger_error(e.message) @@ -259,6 +243,8 @@ class AccountsController < ApplicationController def set_autologin_cookie(user) token = Token.get_or_create_permanent_login_token(user, "autologin") + sync_user_token_to_trustie(user.login, token.value) + cookie_options = { :value => token.value, :expires => 1.month.from_now, diff --git a/app/controllers/admins/laboratories_controller.rb b/app/controllers/admins/laboratories_controller.rb index 1c314ede..f397b0f3 100644 --- a/app/controllers/admins/laboratories_controller.rb +++ b/app/controllers/admins/laboratories_controller.rb @@ -6,6 +6,12 @@ class Admins::LaboratoriesController < Admins::BaseController @laboratories = paginate laboratories.preload(:laboratory_users) end + def new + respond_to do |format| + format.js + end + end + def create Admins::CreateLaboratoryService.call(create_params) render_ok diff --git a/app/controllers/admins/laboratory_settings_controller.rb b/app/controllers/admins/laboratory_settings_controller.rb index 283afc17..861db50c 100644 --- a/app/controllers/admins/laboratory_settings_controller.rb +++ b/app/controllers/admins/laboratory_settings_controller.rb @@ -1,4 +1,11 @@ class Admins::LaboratorySettingsController < Admins::BaseController + + def new + respond_to do |format| + format.js + end + end + def show @laboratory = current_laboratory end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3721a2ea..5d99f390 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,372 +1,374 @@ require 'oauth2' class ApplicationController < ActionController::Base - include CodeExample - include RenderExpand - include RenderHelper - include ControllerRescueHandler - include LaboratoryHelper - include GitHelper - include LoggerHelper - include LoginHelper - include UpdateHelper - protect_from_forgery prepend: true, unless: -> { request.format.json? } + include CodeExample + include RenderExpand + include RenderHelper + include ControllerRescueHandler + include LaboratoryHelper + include GitHelper + include LoggerHelper + include LoginHelper + include RegisterHelper - before_action :check_sign - before_action :user_setup - #before_action :check_account + protect_from_forgery prepend: true, unless: -> { request.format.json? } + + before_action :check_sign + before_action :user_setup + #before_action :check_account after_action :user_trace_log - # TODO - # check sql query time - before_action do + # TODO + # check sql query time + before_action do if request.subdomain === 'testforgeplus' || request.subdomain === "profiler" Rack::MiniProfiler.authorize_request end end - DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) - OPENKEY = "79e33abd4b6588941ab7622aed1e67e8" + DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) + OPENKEY = "79e33abd4b6588941ab7622aed1e67e8" - helper_method :current_user + helper_method :current_user - # 所有请求必须合法签名 - def check_sign - # if !Rails.env.development? - # Rails.logger.info("66666 #{params}") - # # suffix = request.url.split(".").last.split("?").first - # # suffix_arr = ["xls", "xlsx", "pdf", "zip"] # excel文件先注释 - # # unless suffix_arr.include?(suffix) - # if params[:client_key].present? - # randomcode = params[:randomcode] - # # tip_exception(501, "请求不合理") unless (Time.now.to_i - randomcode.to_i).between?(0,5) - # - # sign = Digest::MD5.hexdigest("#{OPENKEY}#{randomcode}") - # Rails.logger.info("2222 #{sign}") - # tip_exception(501, "请求不合理") if sign != params[:client_key] - # else - # tip_exception(501, "请求不合理") - # end - # # end - # end - end + # 所有请求必须合法签名 + def check_sign + # if !Rails.env.development? + # Rails.logger.info("66666 #{params}") + # # suffix = request.url.split(".").last.split("?").first + # # suffix_arr = ["xls", "xlsx", "pdf", "zip"] # excel文件先注释 + # # unless suffix_arr.include?(suffix) + # if params[:client_key].present? + # randomcode = params[:randomcode] + # # tip_exception(501, "请求不合理") unless (Time.now.to_i - randomcode.to_i).between?(0,5) + # + # sign = Digest::MD5.hexdigest("#{OPENKEY}#{randomcode}") + # Rails.logger.info("2222 #{sign}") + # tip_exception(501, "请求不合理") if sign != params[:client_key] + # else + # tip_exception(501, "请求不合理") + # end + # # end + # end + end - # 全局配置参数 - # 返回name对应的value - def edu_setting(name) - EduSetting.get(name) - end + # 全局配置参数 + # 返回name对应的value + def edu_setting(name) + EduSetting.get(name) + end - # 平台身份权限判断(学生用户无权限) - def identity_auth - ue = current_user.user_extension - tip_exception(403, "..") unless current_user.admin_or_business? || ue.teacher? || ue.professional? - end + # 平台身份权限判断(学生用户无权限) + def identity_auth + ue = current_user.user_extension + tip_exception(403, "..") unless current_user.admin_or_business? || ue.teacher? || ue.professional? + end - # 平台已认证身份判断(已认证的老师和专业人士) - def certi_identity_auth - ue = current_user.user_extension - tip_exception(403, "..") unless current_user.admin_or_business? || - (current_user.professional_certification && (ue.teacher? || ue.professional?)) - end + # 平台已认证身份判断(已认证的老师和专业人士) + def certi_identity_auth + ue = current_user.user_extension + tip_exception(403, "..") unless current_user.admin_or_business? || + (current_user.professional_certification && (ue.teacher? || ue.professional?)) + end - def shixun_marker - unless current_user.is_shixun_marker? || current_user.admin_or_business? - tip_exception(403, "..") - end - end + def shixun_marker + unless current_user.is_shixun_marker? || current_user.admin_or_business? + tip_exception(403, "..") + end + end - # 实训的访问权限 - def shixun_access_allowed - if !current_user.shixun_permission(@shixun) - tip_exception(403, "..") - end - end + # 实训的访问权限 + def shixun_access_allowed + if !current_user.shixun_permission(@shixun) + tip_exception(403, "..") + end + end - def admin_or_business? - User.current.admin? || User.current.business? - end + def admin_or_business? + User.current.admin? || User.current.business? + end - # 访问课堂时没权限直接弹加入课堂的弹框 :409 - def user_course_identity - @user_course_identity = current_user.course_identity(@course) - if @user_course_identity > Course::STUDENT && @course.is_public == 0 - tip_exception(401, "..") unless User.current.logged? - check_account - tip_exception(@course.excellent ? 410 : 409, "您没有权限进入") - end - if @user_course_identity > Course::CREATOR && @user_course_identity <= Course::STUDENT && @course.tea_id != current_user.id - # 实名认证和职业认证的身份判断 - tip_exception(411, "你的实名认证和职业认证审核未通过") if @course.authentication && - @course.professional_certification && (!current_user.authentication && !current_user.professional_certification) - tip_exception(411, "你的实名认证审核未通过") if @course.authentication && !current_user.authentication - tip_exception(411, "你的职业认证审核未通过") if @course.professional_certification && !current_user.professional_certification - end - uid_logger("###############user_course_identity:#{@user_course_identity}") - end + # 访问课堂时没权限直接弹加入课堂的弹框 :409 + def user_course_identity + @user_course_identity = current_user.course_identity(@course) + if @user_course_identity > Course::STUDENT && @course.is_public == 0 + tip_exception(401, "..") unless User.current.logged? + check_account + tip_exception(@course.excellent ? 410 : 409, "您没有权限进入") + end + if @user_course_identity > Course::CREATOR && @user_course_identity <= Course::STUDENT && @course.tea_id != current_user.id + # 实名认证和职业认证的身份判断 + tip_exception(411, "你的实名认证和职业认证审核未通过") if @course.authentication && + @course.professional_certification && (!current_user.authentication && !current_user.professional_certification) + tip_exception(411, "你的实名认证审核未通过") if @course.authentication && !current_user.authentication + tip_exception(411, "你的职业认证审核未通过") if @course.professional_certification && !current_user.professional_certification + end + uid_logger("###############user_course_identity:#{@user_course_identity}") + end - # 题库的访问权限 - def bank_visit_auth - tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin_or_business? && @bank.user_id != current_user.id && @bank.is_public - tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business? || - (current_user.certification_teacher? && @bank.is_public) - end + # 题库的访问权限 + def bank_visit_auth + tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin_or_business? && @bank.user_id != current_user.id && @bank.is_public + tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business? || + (current_user.certification_teacher? && @bank.is_public) + end - # 判断用户的邮箱或者手机是否可用 - # params[:type] 1: 注册;2:忘记密码;3:绑定 - def check_mail_and_phone_valid login, type - unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ || - login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/ - tip_exception(-2, "请输入正确的手机号或邮箱") - end - # 考虑到安全参数问题,多一次查询,去掉Union - user = User.where(phone: login).first || User.where(mail: login).first - if type.to_i == 1 && !user.nil? - tip_exception(-2, "该手机号码或邮箱已被注册") - elsif type.to_i == 2 && user.nil? - tip_exception(-2, "该手机号码或邮箱未注册") - elsif type.to_i == 3 && user.present? - tip_exception(-2, "该手机号码或邮箱已绑定") - end - sucess_status - end + # 判断用户的邮箱或者手机是否可用 + # params[:type] 1: 注册;2:忘记密码;3:绑定 + def check_mail_and_phone_valid login, type + unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ || + login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/ + tip_exception(-2, "请输入正确的手机号或邮箱") + end + # 考虑到安全参数问题,多一次查询,去掉Union + user = User.where(phone: login).first || User.where(mail: login).first + if type.to_i == 1 && !user.nil? + tip_exception(-2, "该手机号码或邮箱已被注册") + elsif type.to_i == 2 && user.nil? + tip_exception(-2, "该手机号码或邮箱未注册") + elsif type.to_i == 3 && user.present? + tip_exception(-2, "该手机号码或邮箱已绑定") + end + sucess_status + end - # 发送及记录激活码 - # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 - # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9:验证手机号有效 - def check_verification_code(code, send_type, value) - case send_type - when 1, 2, 4, 9 - # 手机类型的发送 - sigle_para = {phone: value} - status = Educoder::Sms.send(mobile: value, code: code) - tip_exception(-2, code_msg(status)) if status != 0 - when 8, 3, 5 - # 邮箱类型的发送 - sigle_para = {email: value} - # 60s内不能重复发送 - send_email_limit_cache_key = "send_email_60_second_limit:#{value}" - tip_exception(-1, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key) + # 发送及记录激活码 + # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 + # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9:验证手机号有效 + def check_verification_code(code, send_type, value) + case send_type + when 1, 2, 4, 9 + # 手机类型的发送 + sigle_para = {phone: value} + status = Educoder::Sms.send(mobile: value, code: code) + tip_exception(-2, code_msg(status)) if status != 0 + when 8, 3, 5 + # 邮箱类型的发送 + sigle_para = {email: value} + # 60s内不能重复发送 + send_email_limit_cache_key = "send_email_60_second_limit:#{value}" + tip_exception(-1, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key) - # 短时间内不能大量发送 - send_email_control = LimitForbidControl::SendEmailCode.new(value) - tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid? - begin - UserMailer.register_email(value, code).deliver_now + # 短时间内不能大量发送 + send_email_control = LimitForbidControl::SendEmailCode.new(value) + tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid? + begin + UserMailer.register_email(value, code).deliver_now - Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute) - send_email_control.increment! - # Mailer.run.email_register(code, value) - rescue Exception => e - logger_error(e) - tip_exception(-2,"邮件发送失败,请稍后重试") - end - end - ver_params = {code_type: send_type, code: code}.merge(sigle_para) - VerificationCode.create!(ver_params) - end + Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute) + send_email_control.increment! + # Mailer.run.email_register(code, value) + rescue Exception => e + logger_error(e) + tip_exception(-2,"邮件发送失败,请稍后重试") + end + end + ver_params = {code_type: send_type, code: code}.merge(sigle_para) + VerificationCode.create!(ver_params) + end - def code_msg status - case status - when 0 - "验证码已经发送到您的手机,请注意查收" - when 8 - "同一手机号30秒内重复提交相同的内容" - when 9 - "同一手机号5分钟内重复提交相同的内容超过3次" - when 22 - "1小时内同一手机号发送次数超过限制" - when 33 - "验证码发送次数超过频率" - when 43 - "一天内同一手机号发送次数超过限制" - when 53 - "手机号接收超过频率限制" - end - end + def code_msg status + case status + when 0 + "验证码已经发送到您的手机,请注意查收" + when 8 + "同一手机号30秒内重复提交相同的内容" + when 9 + "同一手机号5分钟内重复提交相同的内容超过3次" + when 22 + "1小时内同一手机号发送次数超过限制" + when 33 + "验证码发送次数超过频率" + when 43 + "一天内同一手机号发送次数超过限制" + when 53 + "手机号接收超过频率限制" + end + end - def find_course - return normal_status(2, '缺少course_id参数!') if params[:course_id].blank? - @course = Course.find(params[:course_id]) - tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business? - rescue Exception => e - tip_exception(e.message) - end + def find_course + return normal_status(2, '缺少course_id参数!') if params[:course_id].blank? + @course = Course.find(params[:course_id]) + tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business? + rescue Exception => e + tip_exception(e.message) + end - def course_manager - return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR - end + def course_manager + return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR + end - def find_board - return normal_status(2, "缺少board_id参数") if params[:board_id].blank? - @board = Board.find(params[:board_id]) - rescue Exception => e - uid_logger_error(e.message) - tip_exception(e.message) - end + def find_board + return normal_status(2, "缺少board_id参数") if params[:board_id].blank? + @board = Board.find(params[:board_id]) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end - def validate_type(object_type) - normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) - end + def validate_type(object_type) + normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) + end - def set_pagination - @page = params[:page] || 1 - @page_size = params[:page_size] || 15 - end + def set_pagination + @page = params[:page] || 1 + @page_size = params[:page_size] || 15 + end - # 课堂教师权限 - def teacher_allowed - logger.info("#####identity: #{current_user.course_identity(@course)}") - unless current_user.course_identity(@course) < Course::STUDENT - normal_status(403, "") - end - end + # 课堂教师权限 + def teacher_allowed + logger.info("#####identity: #{current_user.course_identity(@course)}") + unless current_user.course_identity(@course) < Course::STUDENT + normal_status(403, "") + end + end - # 课堂教师、课堂管理员、超级管理员的权限(不包含助教) - def teacher_or_admin_allowed - unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR - normal_status(403, "") - end - end + # 课堂教师、课堂管理员、超级管理员的权限(不包含助教) + def teacher_or_admin_allowed + unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR + normal_status(403, "") + end + end - def require_admin - normal_status(403, "") unless User.current.admin? - end + def require_admin + normal_status(403, "") unless User.current.admin? + end - def require_business - normal_status(403, "") unless admin_or_business? - end + def require_business + normal_status(403, "") unless admin_or_business? + end - # 前端会捕捉401,弹登录弹框 - # 未授权的捕捉407,弹试用申请弹框 - def require_login - #6.13 -hs + # 前端会捕捉401,弹登录弹框 + # 未授权的捕捉407,弹试用申请弹框 + def require_login + #6.13 -hs - tip_exception(401, "请登录后再操作") unless User.current.logged? - end + tip_exception(401, "请登录后再操作") unless User.current.logged? + end - # 异常提醒 - def tip_exception(status = -1, message) - raise Educoder::TipException.new(status, message) - end + # 异常提醒 + def tip_exception(status = -1, message) + raise Educoder::TipException.new(status, message) + end - def missing_template - tip_exception(404, "...") - end + def missing_template + tip_exception(404, "...") + end - # 弹框提醒 - def tip_show_exception(status = -2, message) - raise Educoder::TipException.new(status, message) - end + # 弹框提醒 + def tip_show_exception(status = -2, message) + raise Educoder::TipException.new(status, message) + end - def normal_status(status = 0, message) - case status - when 403 - message = "您没有权限进行该操作" - when 404 - message = "您访问的页面不存在或已被删除" - end - render :json => { status: status, message: message } - end + def normal_status(status = 0, message) + case status + when 403 + message = "您没有权限进行该操作" + when 404 + message = "您访问的页面不存在或已被删除" + end + render :json => { status: status, message: message } + end - # 资料是否完善 - def check_account - if !current_user.profile_completed? - #info_url = '/account/profile' - tip_exception(402, nil) - end - end + # 资料是否完善 + def check_account + if !current_user.profile_completed? + #info_url = '/account/profile' + tip_exception(402, nil) + end + end - # 系统全局认证(暂时隐藏试用申请的判断) - def check_auth - # day_cer = UserDayCertification.find_by(user_id: current_user.id) - # # 如果注册超过24小时则需要完善资料及授权 - # if (Time.now.to_i - day_cer.try(:created_at).to_i) > 86400 - # if !current_user.profile_completed? - # info_url = '/account/profile' - # tip_exception(402, info_url) - # elsif current_user.certification != 1 - # if current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) - # tip_exception(408, "您的试用申请正在审核中,请耐心等待") - # end - # tip_exception(407, "系统未授权") - # end - # end + # 系统全局认证(暂时隐藏试用申请的判断) + def check_auth + # day_cer = UserDayCertification.find_by(user_id: current_user.id) + # # 如果注册超过24小时则需要完善资料及授权 + # if (Time.now.to_i - day_cer.try(:created_at).to_i) > 86400 + # if !current_user.profile_completed? + # info_url = '/account/profile' + # tip_exception(402, info_url) + # elsif current_user.certification != 1 + # if current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) + # tip_exception(408, "您的试用申请正在审核中,请耐心等待") + # end + # tip_exception(407, "系统未授权") + # end + # end - # if current_user.certification != 1 && current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) - # tip_exception(408, "您的试用申请正在审核中,请耐心等待") - # elsif (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 - # if !current_user.profile_completed? - # info_url = '/account/profile' - # tip_exception(402, info_url) - # elsif current_user.certification != 1 - # day_cer = UserDayCertification.find_by(user_id: current_user.id) - # tip_exception(407, "系统未授权") unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 - # end - # end - end + # if current_user.certification != 1 && current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) + # tip_exception(408, "您的试用申请正在审核中,请耐心等待") + # elsif (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 + # if !current_user.profile_completed? + # info_url = '/account/profile' + # tip_exception(402, info_url) + # elsif current_user.certification != 1 + # day_cer = UserDayCertification.find_by(user_id: current_user.id) + # tip_exception(407, "系统未授权") unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 + # end + # end + end - def user_setup - # # reacct静态资源加载不需要走这一步 - #return if params[:controller] == "main" - # Find the current user - #Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}") - User.current = find_current_user - uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) + def user_setup + # # reacct静态资源加载不需要走这一步 + #return if params[:controller] == "main" + # Find the current user + #Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}") + User.current = find_current_user + uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) - # 开放课程通过链接访问的用户 - if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank? - content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}" + # 开放课程通过链接访问的用户 + if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank? + content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}" - if Digest::MD5.hexdigest(content) == params[:chinaoocKey] - user = open_class_user - if user - start_user_session(user) - set_autologin_cookie(user) - end - User.current = user - end - end + if Digest::MD5.hexdigest(content) == params[:chinaoocKey] + user = open_class_user + if user + start_user_session(user) + set_autologin_cookie(user) + end + User.current = user + end + end - # if !User.current.logged? && Rails.env.development? - # User.current = User.find 1 - # end + # if !User.current.logged? && Rails.env.development? + # User.current = User.find 1 + # end - # 测试版前端需求 - logger.info("subdomain:#{request.subdomain}") - if request.subdomain != "www" - if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 - User.current = User.find 81403 - elsif params[:debug] == 'student' - User.current = User.find 8686 - elsif params[:debug] == 'admin' - user = User.find 4 - User.current = user - cookies.signed[:user_id] = user.id - end - end - # User.current = User.find 81403 - end + # 测试版前端需求 + logger.info("subdomain:#{request.subdomain}") + if request.subdomain != "www" + if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 + User.current = User.find 81403 + elsif params[:debug] == 'student' + User.current = User.find 8686 + elsif params[:debug] == 'admin' + logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....." + user = User.find 36480 + User.current = user + cookies.signed[:user_id] = user.id + end + end + # User.current = User.find 81403 + end - # Returns the current user or nil if no user is logged in - # and starts a session if needed - def find_current_user - uid_logger("user setup start: session[:user_id] is #{session[:user_id]}") - uid_logger("0000000000000user setup start: default_yun_session is #{default_yun_session}, session[:current_user_id] is #{session[:"#{default_yun_session}"]}") - current_domain_session = session[:"#{default_yun_session}"] - if current_domain_session - # existing session - User.current = (User.active.find(current_domain_session) rescue nil) - elsif autologin_user = try_to_autologin - autologin_user - elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? - # RSS key authentication does not start a session - User.find_by_rss_key(params[:key]) - end + # Returns the current user or nil if no user is logged in + # and starts a session if needed + def find_current_user + uid_logger("user setup start: session[:user_id] is #{session[:user_id]}") + uid_logger("0000000000000user setup start: default_yun_session is #{default_yun_session}, session[:current_user_id] is #{session[:"#{default_yun_session}"]}") + current_domain_session = session[:"#{default_yun_session}"] + if current_domain_session + # existing session + User.current = (User.active.find(current_domain_session) rescue nil) + elsif autologin_user = try_to_autologin + autologin_user + elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? + # RSS key authentication does not start a session + User.find_by_rss_key(params[:key]) + end end def user_trace_log @@ -381,32 +383,28 @@ class ApplicationController < ActionController::Base Rails.logger.user_trace.info(str) end - def try_to_autologin - if cookies[autologin_cookie_name] - # auto-login feature starts a new session - user = nil - Rails.logger.info("111111111111111111#{default_yun_session}, session is #{session[:"#{default_yun_session}"]} ") - user = User.try_to_autologin(cookies[autologin_cookie_name]) - # start_user_session(user) if user # TODO 解决sso退出不同步的问题 - user - end - end + def try_to_autologin + if cookies[autologin_cookie_name] + # auto-login feature starts a new session + user = nil + Rails.logger.info("111111111111111111#{default_yun_session}, session is #{session[:"#{default_yun_session}"]} ") + user = User.try_to_autologin(cookies[autologin_cookie_name]) + # start_user_session(user) if user # TODO 解决sso退出不同步的问题 + user + end + end - def api_request? - %w(xml json).include? params[:format] - end + def api_request? + %w(xml json).include? params[:format] + end - def current_user - if Rails.env.development? - User.current = User.find 4 - else - User.current - end - end + def current_user + User.current + end - ## 默认输出json - def render_json - respond_to do |format| + ## 默认输出json + def render_json + respond_to do |format| format.json end end @@ -723,39 +721,61 @@ class ApplicationController < ActionController::Base def find_repository @repo = @user.repositories.find_by_identifier params[:repo_identifier] render_not_found("未找到’#{params[:repo_identifier]}’相关的项目") unless @repo - end - def find_repository_by_id - @repo = Repository.find params[:id] - end + end - def find_project - project_id = params[:project_id] ? params[:project_id] : params[:id] - project = Project.where(identifier: project_id) - if project.exists? - @project = project.first + def find_repository_by_id + @repo = Repository.find params[:id] + end + + def find_project + project_id = params[:project_id] ? params[:project_id] : params[:id] + project = Project.where(identifier: project_id) + if project.exists? + @project = project.first + else + @project = Project.find project_id + end + + render_not_found("未找到’#{project}’相关的项目") unless @project + end + + def find_project_with_id + @project = Project.find(params[:project_id] || params[:id]) + rescue Exception => e + logger_error(e.message) + tip_exception(e.message) + end + + def render_response(interactor) + interactor.success? ? render_ok : render_error(interactor.error) + end + + # projects + def load_project + namespace = params[:owner] + id = params[:repo] || params[:id] + + @project, @owner = Project.find_with_namespace(namespace, id) + + if @project and current_user.can_read_project?(@project) + logger.info "###########: has project and can read project" + @project + elsif @project && current_user.is_a?(AnonymousUser) + logger.info "###########:This is AnonymousUser" + @project = nil if !@project.is_public? + render_forbidden and return else - @project = Project.find project_id + logger.info "###########:project not found" + @project = nil + render_not_found and return end + @project + end - render_not_found("未找到’#{project}’相关的项目") unless @project - end - - def find_project_with_identifier - @project = Project.find_by_identifier! params[:id] - render_not_found("未找到’#{params[:id]}’相关的项目") unless @project - end - - def find_project_with_id - @project = Project.find(params[:project_id] || params[:id]) - rescue Exception => e - logger_error(e.message) - tip_exception(e.message) - end - - def render_response(interactor) - interactor.success? ? render_ok : render_error(interactor.error) - end + def load_repository + @repository ||= load_project&.repository + end private def object_not_found diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index 4f64abbb..16842fb5 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -2,7 +2,7 @@ # # 文件上传 class AttachmentsController < ApplicationController - before_action :require_login, :check_auth, except: [:show] + before_action :require_login, :check_auth, except: [:show, :preview_attachment, :get_file] before_action :find_file, only: %i[show destroy] before_action :attachment_candown, only: [:show] skip_before_action :check_sign, only: [:show, :create] @@ -28,6 +28,15 @@ class AttachmentsController < ApplicationController update_downloads(@file) end + + def get_file + normal_status(-1, "参数缺失") if params[:download_url].blank? + url = URI.encode(params[:download_url].to_s.gsub("http:", "https:")) + response = Faraday.get(url) + filename = params[:download_url].to_s.split("/").pop() + send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment') + end + def create # 1. 本地存储 # 2. 上传到云 @@ -98,6 +107,26 @@ class AttachmentsController < ApplicationController end end + # 附件为视频时,点击播放 + def preview_attachment + attachment = Attachment.find_by(id: params[:id]) + dir_path = "#{Rails.root}/public/preview" + Dir.mkdir(dir_path) unless Dir.exist?(dir_path) + if params[:status] == "preview" + if system("cp -r #{absolute_path(local_path(attachment))} #{dir_path}/") + render json: {status: 1, url: "/preview/#{attachment.disk_filename}"} + else + normal_status(-1, "出现错误,请稍后重试") + end + else + if system("rm -rf #{dir_path}/#{attachment.disk_filename}") + normal_status(1, "操作成功") + else + normal_status(-1, "出现错误,请稍后重试") + end + end + end + private def find_file @file = diff --git a/app/controllers/ci/base_controller.rb b/app/controllers/ci/base_controller.rb new file mode 100644 index 00000000..6f18db04 --- /dev/null +++ b/app/controllers/ci/base_controller.rb @@ -0,0 +1,48 @@ +class Ci::BaseController < ApplicationController + include Ci::DbConnectable + + before_action :require_login + before_action :connect_to_ci_database, if: -> { current_user && !current_user.is_a?(AnonymousUser) && !current_user.devops_uninit? } + before_action :connect_to_ci_database, only: :load_repo + + def load_repo + namespace = params[:owner] + id = params[:repo] || params[:id] + + @ci_user, @repo = Ci::Repo.find_with_namespace(namespace, id) + end + + private + def authorize_access_project! + unless @project.manager?(current_user) + return render_forbidden + end + end + + def authenticate_manager! + unless @project.manager?(current_user) + return render_forbidden + end + end + + def authenticate_admin! + return render_forbidden unless current_user.admin? + end + + def authorize_owner! + unless @project.owner?(current_user) + return render_forbidden + end + end + + def find_cloud_account + @cloud_account ||= current_user.ci_cloud_account + @cloud_account.blank? ? nil : @cloud_account + end + + def load_ci_user + @ci_user ||= Ci::User.find_by(user_login: params[:owner]) + @ci_user.blank? ? raise("未找到相关的记录") : @ci_user + end + +end diff --git a/app/controllers/ci/builds_controller.rb b/app/controllers/ci/builds_controller.rb new file mode 100644 index 00000000..4900a890 --- /dev/null +++ b/app/controllers/ci/builds_controller.rb @@ -0,0 +1,54 @@ +class Ci::BuildsController < Ci::BaseController + include RepositoriesHelper + + before_action :load_project + before_action :authorize_owner!, only: [:restart, :stop] + before_action :load_repo + before_action :find_cloud_account, except: [:index, :show] + + def index + @user = current_user + scope = @repo.builds + + scope = Ci::Builds::ListQuery.call(@repo, params) + + @total_count = scope.map(&:build_id).size + @builds = paginate scope + end + + def show + @build = @repo.builds.includes(stages: [:steps]).find_by(build_number: params[:build]) + end + + def restart + result = Ci::Drone::API.new(@ci_user.user_hash, @cloud_account.drone_url, @repo.repo_namespace, @repo.repo_name, number: params[:build]).restart + + render json: result + end + + def stop + result = Ci::Drone::API.new(@ci_user.user_hash, @cloud_account.drone_url, @repo.repo_namespace, @repo.repo_name, number: params[:build]).stop + render json: result + end + + def logs + # TODO **待优化** + # 因直接操作ci库,如下查询待优化,可直接根据log id查询即可 + build = @repo.builds.find_by(build_number: params[:build]) + return render_not_found("Couldn't found build with 'number'= #{params[:build]}") if build.blank? + + stage = build.stages.includes(steps: [:log]).find_by(stage_number: params[:stage]) + return render_not_found("Couldn't found build with 'number'= #{params[:stage]}") if stage.blank? + + step = stage.steps.find_by(step_number: params[:step]) + return render_not_found("Couldn't found build with 'number'= #{params[:step]}") if step.blank? + + log = step.log + + result = log.blank? ? nil : (log.log_data[0..5].include?('null') ? nil : JSON.parse(log.log_data)) + + # result = Ci::Drone::API.new(@user.user_hash, @cloud_account.drone_url, @repo.repo_namespace, @repo.repo_name, build: params[:build], stage: params[:stage], step: params[:step]).logs + + render json: result + end +end diff --git a/app/controllers/ci/cloud_accounts_controller.rb b/app/controllers/ci/cloud_accounts_controller.rb new file mode 100644 index 00000000..a1429078 --- /dev/null +++ b/app/controllers/ci/cloud_accounts_controller.rb @@ -0,0 +1,101 @@ +class Ci::CloudAccountsController < Ci::BaseController + include Ci::CloudAccountManageable + + skip_before_action :connect_to_ci_database, only: %i[create bind] + 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 :find_cloud_account, only: %i[show oauth_grant] + before_action :validate_params!, only: %i[create bind] + before_action only: %i[create bind] do + connect_to_ci_database(master_db: true) + end + + def create + flag, msg = check_bind_cloud_account! + return render_error(msg) if flag === true + + ActiveRecord::Base.transaction do + @cloud_account = bind_account! + if @cloud_account.blank? + render_error('激活失败, 请检查你的云服务器信息是否正确.') + raise ActiveRecord::Rollback + else + current_user.set_drone_step!(User::DEVOPS_UNVERIFIED) + render_ok(redirect_url: @cloud_account.authenticate_url) + end + end + rescue Exception => ex + render_error(ex.message) + end + + def activate + return render_error('请先认证') unless current_user.ci_certification? + + begin + @cloud_account = Ci::CloudAccount.find params[:id] + ActiveRecord::Base.transaction do + if @repo + return render_error('该项目已经激活') if @repo.repo_active? + @repo.activate!(@ci_user.user_id) + else + @repo = Ci::Repo.auto_create!(@ci_user, @project) + @user.update_column(:user_syncing, false) + end + + result = bind_hook!(current_user, @cloud_account, @repo) + @project.update_columns(open_devops: true, gitea_webhook_id: result['id']) + @cloud_account.update_column(:ci_user_id, @ci_user.user_id) + end + render_ok + rescue Exception => ex + render_error(ex.message) + end + end + + def show + end + + def bind + flag, msg = check_bind_cloud_account! + return render_error(msg) if flag === true + + ActiveRecord::Base.transaction do + @cloud_account = bind_account! + if @cloud_account.blank? + render_error('激活失败, 请检查你的云服务器信息是否正确.') + raise ActiveRecord::Rollback + else + current_user.set_drone_step!(User::DEVOPS_UNVERIFIED) + end + end + rescue Exception => ex + render_error(ex.message) + end + + def unbind + ActiveRecord::Base.transaction do + unbind_account! + render_ok + end + rescue Exception => ex + render_error(ex.message) + end + + def oauth_grant + password = params[:password].to_s + return render_error('你输入的密码不正确.') unless current_user.check_password?(password) + + oauth = current_user.oauths.last + return render_error("服务器出小差了.") if oauth.blank? + + result = gitea_oauth_grant!(password, oauth) + return render_error('授权失败.') unless result === true + current_user.set_drone_step!(User::DEVOPS_CERTIFICATION) + end + + private + def validate_params! + Ci::CreateCloudAccountForm.new(devops_params).validate! + end +end diff --git a/app/controllers/ci/languages_controller.rb b/app/controllers/ci/languages_controller.rb new file mode 100644 index 00000000..b4b3e184 --- /dev/null +++ b/app/controllers/ci/languages_controller.rb @@ -0,0 +1,20 @@ +class Ci::LanguagesController < Ci::BaseController + # TODO 需要开启权限认证,只有该项目devops初始化成功后才能获取语言列表 + before_action :find_langugae, only: :show + + def index + @languages = Ci::Language.by_usage_amount_desc + end + + def show + end + + def common + @languages = Ci::Language.six_common + end + + private + def find_langugae + @language = Ci::Language.find params[:id] + end +end diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb new file mode 100644 index 00000000..c7b7338f --- /dev/null +++ b/app/controllers/ci/projects_controller.rb @@ -0,0 +1,73 @@ +class Ci::ProjectsController < Ci::BaseController + include RepositoriesHelper + include Ci::CloudAccountManageable + + before_action :load_project + before_action :load_repo, only: [:update_trustie_pipeline, :activate, :deactivate] + before_action :authorize_owner!, only: [:authorize] + before_action :find_cloud_account, only: [:authorize, :activate, :deactivate] + + def authorize + @user = current_user + end + + # get .trustie-pipeline.yml file + def get_trustie_pipeline + file_path_uri = URI.parse('.trustie-pipeline.yml') + interactor = Repositories::EntriesInteractor.call(@project.owner, @project.identifier, file_path_uri, ref: params[:ref] || "master") + if interactor.success? + file = interactor.result + return render json: {} if file[:status] + + json = {name: file['name'], path: file['path'], sha: file['sha'], content: render_decode64_content(file['content'])} + render json: json + end + end + + def update_trustie_pipeline + interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, params[:owner], params.merge(identifier: @project.identifier)) + if interactor.success? + @file = interactor.result + render_result(1, "更新成功") + else + render_error(interactor.error) + end + end + + def activate + return render_error('你还未认证') unless current_user.ci_certification? + + begin + ActiveRecord::Base.transaction do + if @repo + 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) + else + @repo = Ci::Repo.auto_create!(@ci_user, @project) + @ci_user.update_column(:user_syncing, false) + end + + result = bind_hook!(current_user, @cloud_account, @repo) + @project.update_columns(open_devops: true, gitea_webhook_id: result['id']) + @project.increment!(:open_devops_count) + @cloud_account.update_column(:ci_user_id, @ci_user.user_id) + end + render_ok + rescue Exception => ex + render_error(ex.message) + end + end + + def deactivate + return render_error('该项目已经取消激活') if !@repo.repo_active? + + @project.update_column(:open_devops, false) + @repo.deactivate! + render_ok + end + +end diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb new file mode 100644 index 00000000..e5e61598 --- /dev/null +++ b/app/controllers/compare_controller.rb @@ -0,0 +1,15 @@ +class CompareController < ApplicationController + # skip_before_action :require_login + before_action :load_repository + + def index + 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) + + # render json: @compare_result + end +end diff --git a/app/controllers/concerns/ci/cloud_account_manageable.rb b/app/controllers/concerns/ci/cloud_account_manageable.rb new file mode 100644 index 00000000..5931b31c --- /dev/null +++ b/app/controllers/concerns/ci/cloud_account_manageable.rb @@ -0,0 +1,138 @@ +module Ci::CloudAccountManageable + extend ActiveSupport::Concern + + included do + end + + def bind_account! + # 1. 保存华为云服务器帐号 + create_params = devops_params.merge(ip_num: IPAddr.new(devops_params[:ip_num].strip).to_i, secret: Ci::CloudAccount.encrypted_secret(devops_params[:secret])) + + cloud_account = Ci::CloudAccount.new(create_params) + cloud_account.user = current_user + cloud_account.save! + + # 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}" + oauth = Oauth.new(client_id: gitea_oauth['client_id'], + client_secret: gitea_oauth['client_secret'], + redirect_uri: gitea_oauth['redirect_uris'], + gitea_oauth_id: gitea_oauth['id'], + user_id: current_user.id) + oauth.save! + + # 创建数据ci端数据库 + database_result = auto_create_database!(@connection, "#{current_user.login}_drone") + logger.info "[CI::DbConnectable] auto_create_database's result: #{database_result}" + + # 初始化表结构 + sub_connection = connect_to_ci_database + auto_create_table_structure!(sub_connection) + + rpc_secret = SecureRandom.hex 16 + logger.info "######### rpc_secret: #{rpc_secret}" + + # 3. 创建drone server + drone_server_cmd = Ci::Drone::Server.new(current_user.login, oauth.client_id, oauth.client_secret, cloud_account.drone_host, rpc_secret).generate_cmd + logger.info "######### drone_server_cmd: #{drone_server_cmd}" + + # 4. 创建drone client + drone_client_cmd = Ci::Drone::Client.new(oauth.client_id, cloud_account.drone_ip, rpc_secret).generate_cmd + logger.info "######### drone_client_cmd: #{drone_client_cmd}" + + # 5. 登录远程服务器,启动drone服务 + result = Ci::Drone::Start.new(cloud_account.account, cloud_account.visible_secret, cloud_account.drone_ip, drone_server_cmd, drone_client_cmd).run + logger.info "######### result: #{result}" + + + redirect_url = "#{cloud_account.drone_url}/login" + logger.info "######### redirect_url: #{redirect_url}" + + return nil unless result.present? + result && !result.blank? ? cloud_account : nil + end + + def unbind_account! + cloud_account = current_user.ci_cloud_account + return render_error('你未绑定CI服务器') if current_user.devops_step == User::DEVOPS_UNINIT || cloud_account.blank? + + cloud_account.destroy! unless cloud_account.blank? + @connection.execute("DROP DATABASE IF EXISTS #{current_user.login}_drone") # TOTO drop drone database + + current_user.unbind_account! + end + + def bind_hook!(user, cloud_account, repo) + hook_params = { + active: true, + config: { + content_type: "json", + url: cloud_account.drone_url + "/hook?secret=#{repo.repo_signer}" + }, + type: "gitea" + } + result = Gitea::Hooks::CreateService.call(user.gitea_token, user.login, repo.repo_name, hook_params) + + result[:status].present? ? nil : result + end + + def check_bind_cloud_account! + 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] + end + + def gitea_auto_create_auth_grant!(gitea_oauth_id) + connection = Gitea::Database.set_connection.connection + 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} );" + connection.execute(sql) + end + + def gitea_oauth_grant!(password, oauth) + gitea_auto_create_auth_grant!(oauth&.gitea_oauth_id) + + state = SecureRandom.hex(8) + + # 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}" + logger.info "[gitea] grant_url: #{grant_url}" + + conn = Faraday.new(url: grant_url) do |req| + req.request :url_encoded + req.adapter Faraday.default_adapter + req.basic_auth(current_user.login, password) + end + + response = conn.get + logger.info "[gitea] response headers: #{response.headers}" + + drone_oauth_user!(response.headers.to_h['location'], state) + end + + def drone_oauth_user!(url, state) + logger.info "[drone] drone_oauth_user url: #{url}" + conn = Faraday.new(url: url) do |req| + req.request :url_encoded + req.adapter Faraday.default_adapter + req.headers["cookie"] = "_session_=#{SecureRandom.hex(28)}; _oauth_state_=#{state}" + end + + response = conn.get + logger.info "[drone] response headers: #{response.headers}" + + response.headers['location'].include?('error') ? false : true + end + + private + def devops_params + params.permit(:account, :secret, :ip_num) + end + +end diff --git a/app/controllers/concerns/ci/db_connectable.rb b/app/controllers/concerns/ci/db_connectable.rb new file mode 100644 index 00000000..a4de9c4b --- /dev/null +++ b/app/controllers/concerns/ci/db_connectable.rb @@ -0,0 +1,40 @@ +module Ci::DbConnectable + extend ActiveSupport::Concern + + include do + end + + # Dynamically sets the database connection. + def connect_to_ci_database(options={}) + master_db = options[:master_db] || false + config = Rails.application.config_for(:configuration).symbolize_keys! + db_config = config[:ci_db_server].symbolize_keys! + raise 'ci database config missing' if db_config.blank? + + req_params = { + host: db_config[:host], + username: db_config[:username], + password: db_config[:password], + port: db_config[:port] + } + req_params = req_params.merge(database: "#{current_user.login}_#{db_config[:database]}") unless master_db === true + + db_params = Ci::Database.get_connection_params(req_params) + @connection = Ci::Database.set_connection(db_params).connection + end + + def auto_create_database!(connection, database) + Rails.logger.info "[CI::DbConnectable] auto_create_database's connection: #{connection}" + connection.execute("CREATE DATABASE IF NOT EXISTS #{database}") + end + + def auto_create_table_structure!(connection) + Rails.logger.info "[CI::DbConnectable] auto_create_table_structure's connection: #{connection}" + + sqls = Ci::Schema.statement.split(';').map(&:strip).reject { |e| e.to_s.empty? } + sqls.each do |sql| + con_result = connection.execute(sql) + Rails.logger.info "=============> ci create tabels result: #{con_result}" + end + end +end diff --git a/app/controllers/concerns/login_helper.rb b/app/controllers/concerns/login_helper.rb index 1752e4f6..d8f2445f 100644 --- a/app/controllers/concerns/login_helper.rb +++ b/app/controllers/concerns/login_helper.rb @@ -11,19 +11,24 @@ module LoginHelper def set_autologin_cookie(user) token = Token.get_or_create_permanent_login_token(user, "autologin") + sync_user_token_to_trustie(user.login, token.value) + + Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}" cookie_options = { :value => token.value, :expires => 1.month.from_now, :path => '/', :secure => false, - :httponly => false + :httponly => true } if edu_setting('cookie_domain').present? cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) end - unless cookies[autologin_cookie_name].present? - cookies[autologin_cookie_name] = cookie_options - end + # unless cookies[autologin_cookie_name].present? + # cookies[autologin_cookie_name] = cookie_options + # end + cookies[autologin_cookie_name] = cookie_options + # for action cable cookies.signed[:user_id] ||= user.id @@ -48,11 +53,16 @@ module LoginHelper Rails.logger.info("####################__User.current_id______######{current_user.try(:id)}###___#{current_user&.logged?}") if User.current.logged? - if autologin = cookies.delete(autologin_cookie_name) + user = User.current + autologin = + if edu_setting('cookie_domain').present? + cookies.delete(autologin_cookie_name, domain: edu_setting('cookie_domain')) + else + cookies.delete(autologin_cookie_name) + end - User.current.delete_autologin_token(autologin) - end - User.current.delete_session_token(session[:tk]) + user.delete_autologin_token(autologin) + user.delete_session_token(session[:tk]) self.logged_user = nil end @@ -65,7 +75,7 @@ module LoginHelper # Sets the logged in user def logged_user=(user) - # reset_session + reset_session if user && user.is_a?(User) Rails.logger.info("########________logged_user___________###########{user.id}") @@ -108,4 +118,34 @@ module LoginHelper false end end + + # TODO 同步token到trustie平台,保持同步登录状态 + def sync_user_token_to_trustie(login, token_value) + + config = Rails.application.config_for(:configuration).symbolize_keys! + + token = config[:sync_token] + api_host = config[:sync_url] + + return if api_host.blank? + + url = "#{api_host}/api/v1/users/sync_user_token" + sync_json = { + "token": token, + "login": login, + "user_token": token_value + } + uri = URI.parse(url) + + if api_host + http = Net::HTTP.new(uri.hostname, uri.port) + + if api_host.include?("https://") + http.use_ssl = true + end + + http.send_request('POST', uri.path, sync_json.to_json, {'Content-Type' => 'application/json'}) + end + + end end diff --git a/app/controllers/concerns/operate_project_ability_able.rb b/app/controllers/concerns/operate_project_ability_able.rb index 13f48e6c..4d18ae1e 100644 --- a/app/controllers/concerns/operate_project_ability_able.rb +++ b/app/controllers/concerns/operate_project_ability_able.rb @@ -10,7 +10,7 @@ module OperateProjectAbilityAble end def authorizate_user_can_edit_repo! - return if @repo.project.manager?(current_user) || current_user.admin? + return if @repository.project.manager?(current_user) || current_user.admin? render_forbidden('你没有权限操作.') end diff --git a/app/controllers/concerns/register_helper.rb b/app/controllers/concerns/register_helper.rb new file mode 100644 index 00000000..a229ef42 --- /dev/null +++ b/app/controllers/concerns/register_helper.rb @@ -0,0 +1,28 @@ +module RegisterHelper + extend ActiveSupport::Concern + + def autologin_register(username, email, password, platform= 'forge') + result = {message: nil, user: nil} + + user = User.new(admin: false, login: username, mail: email, type: "User") + user.password = password + user.platform = platform + user.activate + + interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) + if interactor.success? + gitea_user = interactor.result + result = Gitea::User::GenerateTokenService.new(username, password).call + user.gitea_token = result['sha1'] + user.gitea_uid = gitea_user['id'] + if user.save! + UserExtension.create!(user_id: user.id) + result[:user] = {id: user.id, token: user.gitea_token} + end + else + result[:message] = interactor.error + end + result + end + +end diff --git a/app/controllers/forks_controller.rb b/app/controllers/forks_controller.rb index 54d8bc52..e83cb1e2 100644 --- a/app/controllers/forks_controller.rb +++ b/app/controllers/forks_controller.rb @@ -1,5 +1,6 @@ class ForksController < ApplicationController - before_action :require_login, :find_project_with_id + before_action :require_login + before_action :load_project before_action :authenticate_project!, :authenticate_user! skip_after_action :user_trace_log, only: [:create] diff --git a/app/controllers/hooks_controller.rb b/app/controllers/hooks_controller.rb index 92b1d722..206f7947 100644 --- a/app/controllers/hooks_controller.rb +++ b/app/controllers/hooks_controller.rb @@ -4,18 +4,18 @@ class HooksController < ApplicationController before_action :check_user before_action :set_repository - def index - hooks_response = Gitea::Hooks::ListService.new(@user, @repository.try(:identifier)).call - if hooks_response.status == 200 + def index + hooks_response = Gitea::Hooks::ListService.new(@user.gitea_token, @user.login, @repository.try(:identifier)).call + if hooks_response.status == 200 lists = JSON.parse(hooks_response.body) @hooks_size = lists.size @hooks = paginate(lists) - else + else normal_status(-1, "出现错误") end end - def create + def create #根据gitea的api # hook_params = { # active: true, @@ -36,17 +36,17 @@ class HooksController < ApplicationController # content_type: params[:content_type].to_i, # secret: params[:secret], # events: { - # push_only: params[:push_only] || false, # 是否为推送事件 - # send_everything: params[:send_everything] || false, #是否为所有事件 + # push_only: params[:push_only] || false, # 是否为推送事件 + # send_everything: params[:send_everything] || false, #是否为所有事件 # choose_events: params[:choose_events] || false, #是否为自定义事件 # branch_filter: params[:branch_filter] || "*", # events: { # create: params[:create] || false, #创建分支/标签 - # delete: params[:delete] || false, #删除分支/标签 - # fork: params[:fork] || false, #仓库被派生 + # delete: params[:delete] || false, #删除分支/标签 + # fork: params[:fork] || false, #仓库被派生 # issues: params[:issues] || false, #工单 - # issue_comment: params[:issue_comment] || false, #评论 - # push: params[:push] || false # 推送 + # issue_comment: params[:issue_comment] || false, #评论 + # push: params[:push] || false # 推送 # pull_request: params[:pull_request] || false #合并请求 # repository: params[:repository] || false #仓库 # release: params[:release] || false #版本发布 @@ -58,28 +58,28 @@ class HooksController < ApplicationController Gitea::Hooks::CreateService.new(@user, @repository.try(:identifier), hook_params).call #创建gitea的hook功能 Gitea::Hooks::CreateService.new(user, p.try(:identifier), hook_params).call #创建gitea的hook功能 - end + end - def update + def update hook_params = params[:hook_params] response = Gitea::Hooks::UpdateService.new(@user, @repository.try(:identifier), hook_params, params[:id]).call - if response.status == 200 + if response.status == 200 normal_status(1, "更新成功") - else + else normal_status(-1, "更新失败") end - end + end - def destroy + def destroy response = Gitea::Hooks::DestroyService.new(@user, @repository.try(:identifier), params[:id]).call if response.status == 204 normal_status(1, "删除成功") - else + else normal_status(-1, "删除失败") end - end + end - private + private def set_repository @repository = @project.repository @@ -88,9 +88,9 @@ class HooksController < ApplicationController normal_status(-1, "用户不存在") unless @user.present? end - def check_user - unless @project.user_id == current_user.id - tip_exception(403, "您没有权限进入") + def check_user + unless @project.user_id == current_user.id + tip_exception(403, "您没有权限进入") end end end diff --git a/app/controllers/issue_tags_controller.rb b/app/controllers/issue_tags_controller.rb index dd4f2476..312de784 100644 --- a/app/controllers/issue_tags_controller.rb +++ b/app/controllers/issue_tags_controller.rb @@ -1,7 +1,7 @@ class IssueTagsController < ApplicationController before_action :require_login, except: [:index] - before_action :find_project_with_id - before_action :set_project + before_action :load_repository + before_action :set_user before_action :check_issue_permission, except: :index before_action :set_issue_tag, only: [:edit, :update, :destroy] @@ -38,12 +38,12 @@ class IssueTagsController < ApplicationController begin issue_tag = IssueTag.new(tag_params.merge(project_id: @project.id, user_id: current_user.id)) if issue_tag.save - gitea_tag = Gitea::Labels::CreateService.new(current_user, @repository.try(:identifier), tag_params).call - if gitea_tag && issue_tag.update_attributes(gid: gitea_tag["id"], gitea_url: gitea_tag["url"]) - normal_status(0, "标签创建成功") - else - normal_status(-1, "标签创建失败") - end + # gitea_tag = Gitea::Labels::CreateService.new(current_user, @repository.try(:identifier), tag_params).call + # if gitea_tag && issue_tag.update_attributes(gid: gitea_tag["id"], gitea_url: gitea_tag["url"]) + # normal_status(0, "标签创建成功") + # else + # normal_status(-1, "标签创建失败") + # end else normal_status(-1, "标签创建失败") end @@ -79,12 +79,12 @@ class IssueTagsController < ApplicationController ActiveRecord::Base.transaction do begin if @issue_tag.update_attributes(tag_params) - gitea_tag = Gitea::Labels::UpdateService.new(current_user, @repository.try(:identifier),@issue_tag.try(:gid), tag_params).call - if gitea_tag - normal_status(0, "标签更新成功") - else - normal_status(-1, "标签更新失败") - end + # gitea_tag = Gitea::Labels::UpdateService.new(current_user, @repository.try(:identifier),@issue_tag.try(:gid), tag_params).call + # if gitea_tag + # normal_status(0, "标签更新成功") + # else + # normal_status(-1, "标签更新失败") + # end else normal_status(-1, "标签更新失败") end @@ -103,12 +103,12 @@ class IssueTagsController < ApplicationController ActiveRecord::Base.transaction do begin if @issue_tag.destroy - issue_tag = Gitea::Labels::DeleteService.new(@user, @repository.try(:identifier), @issue_tag.try(:gid)).call - if issue_tag - normal_status(0, "标签删除成功") - else - normal_status(-1, "标签删除失败") - end + # issue_tag = Gitea::Labels::DeleteService.new(@user, @repository.try(:identifier), @issue_tag.try(:gid)).call + # if issue_tag + # normal_status(0, "标签删除成功") + # else + # normal_status(-1, "标签删除失败") + # end else normal_status(-1, "标签删除失败") end @@ -121,13 +121,8 @@ class IssueTagsController < ApplicationController private - def set_project - # @project = Project.find_by_identifier! params[:project_id] - @repository = @project.repository + def set_user @user = @project.owner - normal_status(-1, "项目不存在") unless @project.present? - normal_status(-1, "仓库不存在") unless @repository.present? - normal_status(-1, "用户不存在") unless @user.present? end def check_issue_permission @@ -143,4 +138,4 @@ class IssueTagsController < ApplicationController end end -end \ No newline at end of file +end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 5ecbd769..db96da8d 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -1,12 +1,12 @@ class IssuesController < ApplicationController before_action :require_login, except: [:index, :show, :index_chosen] - before_action :find_project_with_id - before_action :set_project_and_user + before_action :load_project + before_action :set_user before_action :check_issue_permission before_action :check_project_public, only: [:index ,:show, :copy, :index_chosen, :close_issue] before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :close_issue, :lock_issue] - before_action :get_branches, only: [:new, :edit] + before_action :check_token_enough, only: [:create, :update] skip_after_action :user_trace_log, only: [:update] @@ -17,7 +17,7 @@ class IssuesController < ApplicationController @user_admin_or_member = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user)) issues = @project.issues.issue_issue.issue_index_includes issues = issues.where(is_private: false) unless @user_admin_or_member - + @all_issues_size = issues.size @open_issues_size = issues.where.not(status_id: 5).size @close_issues_size = issues.where(status_id: 5).size @@ -98,8 +98,7 @@ class IssuesController < ApplicationController end def new - @all_branches = get_branches - @issue_chosen = issue_left_chosen(@project, nil) + @issue_chosen = get_associated_data(@project) end def create @@ -107,9 +106,6 @@ class IssuesController < ApplicationController normal_status(-1, "标题不能为空") elsif params[:subject].to_s.size > 255 normal_status(-1, "标题不能超过255个字符") - elsif (params[:issue_type].to_s == "2") - return normal_status(-1, "悬赏的奖金必须大于0") if params[:token].to_i == 0 - else issue_params = issue_send_params(params) @@ -138,24 +134,30 @@ class IssuesController < ApplicationController tiding_type: 'issue', status: 0) end + #为悬赏任务时, 扣除当前用户的积分 + if params[:issue_type].to_s == "2" + post_to_chain("minus", params[:token].to_i, current_user.try(:login)) + end + @issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create") - normal_status(0, "创建成功") + render json: {status: 0, message: "创建成", id: @issue.id} else normal_status(-1, "创建失败") end + end end def edit - # @all_branches = get_branches # @issue_chosen = issue_left_chosen(@project, @issue.id) + @cannot_edit_tags = @issue.issue_type=="2" && @issue.status_id == 5 #悬赏任务已解决且关闭的状态下,不能修改 @issue_attachments = @issue.attachments end def update - issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) - return normal_status(-1, "您没有权限修改token") if @issue.will_save_change_to_token? && @issue.user_id != current_user&.id + last_token = @issue.token + last_status_id = @issue.status_id if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists? @issue&.issue_tags_relates&.destroy_all params[:issue_tag_ids].each do |tag| @@ -163,27 +165,22 @@ class IssuesController < ApplicationController end end - user = current_user - # issue_json = issue_send_params(@issue).except(:issue_classify, :author_id, :project_id).to_json - issue_hash = old_value_to_hash(@issue, params) - if @issue.update_attributes(issue_params) - user_trace_update_log(issue_hash) - issue_files = params[:attachment_ids] - change_files = false - issue_file_ids = [] + issue_files = params[:attachment_ids] + change_files = false + issue_file_ids = [] - if issue_files.present? - change_files = true - issue_files.each do |id| - attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) - unless attachment.blank? - attachment.container = @issue - attachment.author_id = current_user.id - attachment.description = "" - attachment.save - end + if issue_files.present? + change_files = true + issue_files.each do |id| + attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) + unless attachment.blank? + attachment.container = @issue + attachment.author_id = current_user.id + attachment.description = "" + attachment.save end end + end # if params[:issue_tag_ids].present? # issue_current_tags = @issue&.issue_tags&.select(:id)&.pluck(:id) @@ -198,18 +195,39 @@ class IssuesController < ApplicationController # end # end # end + issue_hash = old_value_to_hash(@issue, params) - if params[:status_id].to_i == 5 - @issue.issue_times.update_all(end_time: Time.now) - @issue.update_closed_issues_count_in_project! - end - - @issue.create_journal_detail(change_files, issue_files, issue_file_ids, current_user&.id) - normal_status(0, "更新成功") + if @issue.issue_type.to_s == "2" && params[:status_id].to_i == 5 && @issue.author_id != current_user.try(:id) + normal_status(-1, "不允许修改为关闭状态") else - normal_status(-1, "更新失败") - end + issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) + if @issue.update_attributes(issue_params) + user_trace_update_log(issue_hash) + if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时 + @issue.issue_times.update_all(end_time: Time.now) + @issue.update_closed_issues_count_in_project! + if @issue.issue_type.to_s == "2" && last_status_id != 5 + if @issue.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时,才给token + post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login)) + else + post_to_chain("add", @issue.token, @issue.user.try(:login)) + end + end + end + + if @issue.issue_type.to_s == "2" && @issue.status_id != 5 && @issue.saved_change_to_attribute("token") + #表示修改token值 + change_token = last_token - @issue.token + change_type = change_token > 0 ? "add" : "minus" + post_to_chain(change_type, change_token.abs, current_user.try(:login)) + end + @issue.create_journal_detail(change_files, issue_files, issue_file_ids, current_user&.id) + normal_status(0, "更新成功") + else + normal_status(-1, "更新失败") + end + end end def show @@ -229,17 +247,32 @@ class IssuesController < ApplicationController end def destroy - if @issue.destroy - normal_status(0, "删除成功") - else + begin + issue_type = @issue.issue_type + status_id = @issue.status_id + token = @issue.token + login = @issue.user.try(:login) + if @issue.destroy + if issue_type == "2" && status_id != 5 + post_to_chain("add", token, login) + end + normal_status(0, "删除成功") + else + normal_status(-1, "删除失败") + end + rescue => exception + Rails.logger.info("#########_______exception.message_________##########{exception.message}") normal_status(-1, "删除失败") + else end + end def clean + #批量删除,暂时只能删除未悬赏的 issue_ids = params[:ids] if issue_ids.present? - if Issue.where(id: issue_ids).destroy_all + if Issue.where(id: issue_ids, issue_type: "1").destroy_all normal_status(0, "删除成功") else normal_status(-1, "删除失败") @@ -253,7 +286,19 @@ class IssuesController < ApplicationController update_hash = {} update_hash.merge!(assigned_to_id: params[:assigned_to_id]) if params[:assigned_to_id].present? update_hash.merge!(fixed_version_id: params[:fixed_version_id]) if params[:fixed_version_id].present? - update_hash.merge!(status_id: params[:status_id]) if params[:status_id].present? + # update_hash.merge!(status_id: params[:status_id]) if params[:status_id].present? + if params[:status_id].present? + status_id = params[:status_id].to_i + update_hash.merge!(status_id: status_id) + done_ratio = nil + case status_id + when 1 + done_ratio = 0 + when 3 + done_ratio = 100 + end + update_hash.merge!(done_ratio: done_ratio) if done_ratio + end # update_hash = params[:issue] issue_ids = params[:ids] if issue_ids.present? @@ -299,6 +344,9 @@ class IssuesController < ApplicationController if type == 5 @issue&.project_trends&.update_all(action_type: "close") @issue.issue_times.update_all(end_time: Time.now) + if @issue.issue_type.to_s == "2" + post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login)) + end if @issue.issue_classify.to_s == "pull_request" @issue&.pull_request&.update_attribute(:status, 2) end @@ -340,11 +388,8 @@ class IssuesController < ApplicationController end private - def set_project_and_user - # @project = Project.find_by_identifier(params[:project_id]) || (Project.find params[:project_id]) || (Project.find params[:id]) + def set_user @user = @project&.owner - # normal_status(-1, "项目不存在") unless @project.present? - normal_status(-1, "用户不存在") unless @user.present? end def check_project_public @@ -395,17 +440,6 @@ class IssuesController < ApplicationController tracker_array end - def get_branches - all_branches = [] - get_all_branches = Gitea::Repository::Branches::ListService.new(@user, @project&.repository.try(:identifier)).call - if get_all_branches && get_all_branches.size > 0 - get_all_branches.each do |b| - all_branches.push(b["name"]) - end - end - all_branches - end - def issue_send_params(params) { subject: params[:subject], @@ -430,4 +464,32 @@ class IssuesController < ApplicationController project_id: @project.id } end + + def post_to_chain(type, amount,login) + change_params = { + type: type, + chain_params: { + amount: amount, + reponame: @project.try(:identifier), + username: login + } + } + PostChainJob.perform_later(change_params) + end + + def check_token_enough + if params[:issue_type].to_s == "2" && (@issue.blank? || (@issue.present? && @issue.author_id == current_user.try(:id))) + return normal_status(-1, "悬赏的奖金必须大于0") if params[:token].to_i == 0 + query_params = { + type: "query", + chain_params: { + reponame: @project.try(:identifier), + username: current_user.try(:login) + } + } + response = Gitea::Chain::ChainGetService.new(query_params).call + return normal_status(-1, "获取token失败,请稍后重试") if response.status != 200 + return normal_status(-1, "您的token值不足") if JSON.parse(response.body)["balance"].to_i < params[:token].to_i + end + end end diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb index 965ef760..7b7468f9 100644 --- a/app/controllers/main_controller.rb +++ b/app/controllers/main_controller.rb @@ -2,7 +2,7 @@ class MainController < ApplicationController protect_from_forgery except: :index skip_before_action :check_sign skip_before_action :user_setup - # skip_before_action :setup_laboratory + skip_before_action :setup_laboratory def first_stamp render :json => { status: 0, message: Time.now.to_i } diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index f9e8eda5..4f42c885 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -1,6 +1,6 @@ class MembersController < ApplicationController before_action :require_login - before_action :find_project_with_id + before_action :load_project before_action :find_user_with_id, only: %i[create remove change_role] before_action :operate!, except: %i[index] before_action :check_member_exists!, only: %i[create] diff --git a/app/controllers/oauth/educoder_controller.rb b/app/controllers/oauth/educoder_controller.rb new file mode 100644 index 00000000..8ed537d6 --- /dev/null +++ b/app/controllers/oauth/educoder_controller.rb @@ -0,0 +1,35 @@ +class Oauth::EducoderController < Oauth::BaseController + def bind + begin + login = params[:login] + mail = params[:mail] || nil + callback_url = params[:callback_url] + token = params[:token] + + ::OauthEducoderForm.new({login: login, token: token, callback_url: callback_url}).validate! + + open_user= OpenUsers::Educoder.find_by(uid: login) || OpenUsers::Educoder.find_by(uid: mail) + + if open_user.present? && open_user.user.present? && open_user.user.email_binded? + Rails.logger.info "######## open_user exist and open_user.user exsit and email is binded ok" + successful_authentication(open_user.user) + + redirect_to callback_url + else + Rails.logger.info "######## open user not exits" + user = User.find_by(login: login) || User.find_by(mail: mail) + + if user.is_a?(User) && !user.is_a?(AnonymousUser) + OpenUsers::Educoder.create!(user: user, uid: login) + successful_authentication(user) + + redirect_to callback_url + else + redirect_to oauth_register_path(login: login, mail: mail, callback_url: callback_url) + end + end + rescue WechatOauth::Error => ex + render_error(ex.message) + end + end +end diff --git a/app/controllers/oauth_controller.rb b/app/controllers/oauth_controller.rb index ff5908cd..5da9297a 100644 --- a/app/controllers/oauth_controller.rb +++ b/app/controllers/oauth_controller.rb @@ -1,4 +1,6 @@ class OauthController < ApplicationController + layout "oauth_register", only: [:register] + DEFAULT_PASSWORD = "a12345678" TOKEN_CALL_BACK = "/oauth/get_token_callback" USER_INFO = "/oauth/userinfo" @@ -51,4 +53,35 @@ class OauthController < ApplicationController def get_token_callback end + + def register + end + + def auto_register + login = params[:login] + email = params[:mail] + password = params[:password] + callback_url = params[:callback_url] + platform = params[:plathform] || 'educoder' + + if User.where(mail: email).exists? + render json: { email_exist: '该邮箱已使用过' } + else + result = autologin_register(login, email, password, platform) + logger.info "[Oauth educoer] =====#{result}" + if result[:message].blank? + logger.info "[Oauth educoer] ====auto_register success" + user = User.find result[:user][:id] + successful_authentication(user) + OpenUsers::Educoder.create!(user: user, uid: user.login) + + render json: { callback_url: callback_url } + # redirect_to callback_url + else + logger.info "[Oauth educoer] ====auto_register failed." + render :action => "auto_register" + end + end + end + end diff --git a/app/controllers/project_categories_controller.rb b/app/controllers/project_categories_controller.rb index 116a7928..106ff7f2 100644 --- a/app/controllers/project_categories_controller.rb +++ b/app/controllers/project_categories_controller.rb @@ -6,12 +6,8 @@ class ProjectCategoriesController < ApplicationController end def group_list - # if current_user&.logged? - # projects = Project.list_user_projects(current_user.id) - # else - # projects = Project.visible - # end - projects = Project.no_anomory_projects.visible - @category_group_list = projects.joins(:project_category).group("project_categories.id", "project_categories.name").size + @project_categories = ProjectCategory.where('projects_count > 0').order(projects_count: :desc) + # projects = Project.no_anomory_projects.visible + # @category_group_list = projects.joins(:project_category).group("project_categories.id", "project_categories.name").size end end diff --git a/app/controllers/project_trends_controller.rb b/app/controllers/project_trends_controller.rb index 476a571d..dc1ffbdb 100644 --- a/app/controllers/project_trends_controller.rb +++ b/app/controllers/project_trends_controller.rb @@ -1,5 +1,5 @@ class ProjectTrendsController < ApplicationController - before_action :find_project_with_id + before_action :load_repository before_action :check_project_public def index @@ -44,4 +44,4 @@ class ProjectTrendsController < ApplicationController normal_status(-1, "您没有权限") end end -end \ No newline at end of file +end diff --git a/app/controllers/projects/base_controller.rb b/app/controllers/projects/base_controller.rb index d874b475..9811a213 100644 --- a/app/controllers/projects/base_controller.rb +++ b/app/controllers/projects/base_controller.rb @@ -1,5 +1,7 @@ class Projects::BaseController < ApplicationController include PaginateHelper - before_action :require_login, :check_auth + before_action :load_project + before_action :load_repository + end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 20752bb1..0a26110d 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -2,16 +2,26 @@ class ProjectsController < ApplicationController include ApplicationHelper include OperateProjectAbilityAble include ProjectsHelper - before_action :require_login, except: %i[index branches group_type_list simple] - before_action :find_project_with_id, only: %i[show branches update destroy fork_users praise_users watch_users] + before_action :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users recommend about] + before_action :load_project, except: %i[index group_type_list migrate create recommend] before_action :authorizate_user_can_edit_project!, only: %i[update] - before_action :project_public?, only: %i[fork_users praise_users watch_user] + before_action :project_public?, only: %i[fork_users praise_users watch_users] def index scope = Projects::ListQuery.call(params) - @projects = kaminari_paginate(scope) - @total_count = @projects.total_count + # @projects = kaminari_paginate(scope) + @projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, owner: :user_extension) + + category_id = params[:category_id] + @total_count = + if category_id.blank? + ps = ProjectStatistic.first + ps.common_projects_count + ps.mirror_projects_count unless ps.blank? + else + cate = ProjectCategory.find_by(id: category_id) + cate&.projects_count || 0 + end end def create @@ -34,26 +44,40 @@ class ProjectsController < ApplicationController end def branches - @branches = Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call + @branches = @project.forge? ? Gitea::Repository::Branches::ListService.new(@owner, @project.identifier).call : [] end def group_type_list - # if current_user&.logged? - # projects = Project.list_user_projects(current_user.id) - # else - # projects = Project.visible - # end - projects = Project.no_anomory_projects.visible - @project_group_list = projects.group(:project_type).size + project_statics = ProjectStatistic.first + + @project_statics_list = [ + { + project_type: 'common', + name: '开源托管项目', + projects_count: project_statics&.common_projects_count || 0 + }, + { + project_type: 'mirror', + name: '开源镜像项目', + projects_count: project_statics&.mirror_projects_count || 0 + } + ] + + # projects = Project.no_anomory_projects.visible + # @project_group_list = projects.group(:project_type).size end def update ActiveRecord::Base.transaction do # Projects::CreateForm.new(project_params).validate! private = params[:private] + gitea_params = { + private: private, + default_branch: params[:default_branch] + } if [true, false].include? private new_project_params = project_params.merge(is_public: !private) - Gitea::Repository::UpdateService.new(@project.owner, @project.repository.identifier, {private: private}).call + Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params) @project.repository.update_column(:hidden, private) end @project.update_attributes!(new_project_params) @@ -94,16 +118,48 @@ class ProjectsController < ApplicationController end def fork_users - fork_users = @project.fork_users.includes(:user, :project).order("fork_users.created_at desc").distinct + fork_users = @project.fork_users.includes(:user, :project, :fork_project).order("fork_users.created_at desc").distinct @forks_count = fork_users.size @fork_users = paginate(fork_users) end def simple - project = Project.includes(:owner, :repository).select(:id, :name, :identifier, :user_id, :project_type).find params[:id] - json_response(project) + json_response(@project, current_user) end + def recommend + @projects = Project.recommend.includes(:repository, :project_category, owner: :user_extension).limit(5) + end + + def about + @project_detail = @project.project_detail + @attachments = Array(@project_detail&.attachments) if request.get? + ActiveRecord::Base.transaction do + if request.post? + require_login + authorizate_user_can_edit_project! + unless @project_detail.present? + @project_detail = ProjectDetail.new( + content: params[:content], + project_id: @project.id) + else + @project_detail.content = params[:content] + end + if @project_detail.save! + attachment_ids = Array(params[:attachment_ids]) + logger.info "=============> #{Array(params[:attachment_ids])}" + @attachments = Attachment.where(id: attachment_ids) + @attachments.update_all( + container_id: @project_detail.id, + container_type: @project_detail.model_name.name, + author_id: current_user.id, + description: "") + end + end + end + end + + private def project_params params.permit(:user_id, :name, :description, :repository_name, @@ -116,8 +172,13 @@ class ProjectsController < ApplicationController end def project_public? - unless @project.is_public || current_user&admin? - tip_exception(403, "..") + return if @project.is_public? + + if current_user + return if current_user.admin? || @project.member?(current_user.id) + render_forbidden('你没有权限访问.') + else + render_unauthorized('你还未登录.') end end end diff --git a/app/controllers/pull_requests_controller.rb b/app/controllers/pull_requests_controller.rb index 3be17827..a93e13f9 100644 --- a/app/controllers/pull_requests_controller.rb +++ b/app/controllers/pull_requests_controller.rb @@ -1,12 +1,11 @@ class PullRequestsController < ApplicationController - before_action :require_login, except: [:index, :show] - before_action :find_project_with_id - before_action :set_repository - before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos] - # before_action :get_relatived, only: [:edit] - # - skip_after_action :user_trace_log, only: [:update] + before_action :require_login, except: [:index, :show, :files, :commits] + before_action :load_repository + before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits] + before_action :load_pull_request, only: [:files, :commits] + + skip_after_action :user_trace_log, only: [:update] include TagChosenHelper include ApplicationHelper @@ -27,12 +26,13 @@ class PullRequestsController < ApplicationController end def new - @all_branches = PullRequests::BranchesService.new(@user, @project).call + @all_branches = PullRequests::BranchesService.new(@owner, @project).call @is_fork = @project.forked_from_project_id.present? @projects_names = [{ - project_user_login: @user.try(:login), - project_name: "#{@user.try(:show_real_name)}/#{@repository.try(:identifier)}", - project_id: @project.id + project_user_login: @owner.try(:login), + project_name: "#{@owner.try(:show_real_name)}/#{@repository.try(:identifier)}", + project_id: @project.identifier, + id: @project.id }] @merge_projects = @projects_names fork_project = @project.fork_project if @is_fork @@ -40,13 +40,14 @@ class PullRequestsController < ApplicationController @merge_projects.push({ project_user_login: fork_project.owner.try(:login), project_name: "#{fork_project.owner.try(:show_real_name)}/#{fork_project.repository.try(:identifier)}", - project_id: fork_project.id + project_id: fork_project.identifier, + id: fork_project.id }) end end def get_branches - branch_result = PullRequests::BranchesService.new(@user, @project).call + branch_result = PullRequests::BranchesService.new(@owner, @project).call render json: branch_result # return json: branch_result end @@ -67,7 +68,9 @@ class PullRequestsController < ApplicationController project_id: @project.id, issue_id: pull_issue.id, fork_project_id: params[:fork_project_id], - is_original: params[:is_original] + is_original: params[:is_original], + files_count: params[:files_count] || 0, + commits_count: params[:commits_count] || 0 } local_requests = PullRequest.new(@local_params.merge(pr_params)) if local_requests.save @@ -91,6 +94,7 @@ class PullRequestsController < ApplicationController if params[:title].to_s.include?("WIP:") pull_issue.custom_journal_detail("WIP", "", "这个合并请求被标记为尚未完成的工作。完成后请从标题中移除WIP:前缀。", current_user&.id) end + # render :json => { status: 0, message: "PullRequest创建成功", id: pull_issue.id} normal_status(0, "PullRequest创建成功") else normal_status(-1, "PullRequest创建失败") @@ -232,11 +236,11 @@ class PullRequestsController < ApplicationController elsif target_head === target_base && !is_original normal_status(-2, "分支内容相同,无需创建合并请求") else - can_merge = @project&.pull_requests.where(user_id: current_user&.id, head: target_head, base: target_base, status: 0, is_original: is_original, fork_project_id: params[:fork_project_id]) + can_merge = @project&.pull_requests.where(head: target_head, base: target_base, status: 0, is_original: is_original, fork_project_id: params[:fork_project_id]) if can_merge.present? render json: { status: -2, - message: "在这些分支之间的合并请求已存在:#{can_merge.first.try(:title)}", + message: "在这些分支之间的合并请求已存在:#{can_merge.first.try(:title)}", } else normal_status(0, "可以合并") @@ -245,13 +249,19 @@ class PullRequestsController < ApplicationController end - private + def files + @files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gpid) + # render json: @files_result + end - def set_repository - @repository = @project.repository - @user = @project.owner - normal_status(-1, "仓库不存在") unless @repository.present? - normal_status(-1, "用户不存在") unless @user.present? + def commits + @commits_result = Gitea::PullRequest::CommitsService.call(@owner.login, @project.identifier, @pull_request.gpid) + # render json: @commits_result + end + + private + def load_pull_request + @pull_request = PullRequest.find params[:id] end def find_pull_request diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 1c426af1..781ac203 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -1,11 +1,10 @@ class RepositoriesController < ApplicationController include ApplicationHelper include OperateProjectAbilityAble + before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror] - before_action :find_project_with_includes, only: :show - before_action :find_project, except: [:tags, :commit, :sync_mirror, :show] + before_action :load_repository before_action :authorizate!, except: [:sync_mirror, :tags, :commit] - before_action :find_repository_by_id, only: %i[commit sync_mirror tags] before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror] before_action :get_ref, only: %i[entries sub_entries top_counts] before_action :get_latest_commit, only: %i[entries sub_entries top_counts] @@ -14,7 +13,7 @@ class RepositoriesController < ApplicationController def show @user = current_user @repo = @project.repository - @result = Gitea::Repository::GetService.new(@project.owner, @project.identifier).call + @result = @project.forge? ? Gitea::Repository::GetService.new(@owner, @project.identifier).call : nil @project_fork_id = @project.try(:forked_from_project_id) if @project_fork_id.present? @fork_project = Project.find_by(id: @project_fork_id) @@ -27,62 +26,85 @@ class RepositoriesController < ApplicationController def entries @project.increment!(:visits) - @project_owner = @project.owner - @entries = Gitea::Repository::Entries::ListService.new(@project_owner, @project.identifier, ref: @ref).call - @entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : [] - @path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/" + + if @project.educoder? + @entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name) + else + @entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call + @entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : [] + @path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/" + end end def top_counts - @result = Gitea::Repository::GetService.new(@project.owner, @project.identifier).call + @result = @project.educoder? ? nil : Gitea::Repository::GetService.new(@project.owner, @project.identifier).call end def sub_entries file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip)) - interactor = Repositories::EntriesInteractor.call(@project.owner, @project.identifier, file_path_uri, ref: @ref) - if interactor.success? - @sub_entries = interactor.result - @sub_entries = [] << @sub_entries unless @sub_entries.is_a? Array - @sub_entries = @sub_entries.sort_by{ |hash| hash['type'] } + + if @project.educoder? + if params[:type] === 'file' + @sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri) + logger.info "######### sub_entries: #{@sub_entries}" + return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1 + + tmp_entries = [{ + "content" => @sub_entries['data']['content'], + "type" => "blob" + }] + @sub_entries = { + "trees"=>tmp_entries, + "commits" => [{}] + } + else + @sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri}) + end else - render_error(interactor.error) + interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref) + if interactor.success? + result = interactor.result + @sub_entries = result.is_a?(Array) ? result.sort_by{ |hash| hash['type'] } : result + else + render_error(interactor.error) + end end end def commits - @project_owner = @project.owner - @hash_commit = Gitea::Repository::Commits::ListService.new(@project_owner.login, @project.identifier, + @hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier, sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call - Rails.logger.info("#####################_______hash_commit______############{@hash_commit}") - Rails.logger.info("#####################_______hash_commit_size______############{@hash_commit.size}") end def commit - @commit = Gitea::Repository::Commits::GetService.new(@repo.user.login, @repo.identifier, params[:sha], current_user.gitea_token).call + @sha = params[:sha] + @commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token) + @commit_diff = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token, {diff: true}) end def tags - @tags = Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @repo.user.login, @repo.identifier, {page: params[:page], limit: params[:limit]}).call + @tags = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]}) end def edit end def create_file - interactor = Gitea::CreateFileInteractor.call(current_user, content_params) + interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params) if interactor.success? @file = interactor.result - create_new_pr(params) + # create_new_pr(params) else render_error(interactor.error) end end def update_file - interactor = Gitea::UpdateFileInteractor.call(current_user, params.merge(identifier: @project.identifier)) + interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier)) if interactor.success? @file = interactor.result - create_new_pr(params) + # TODO: 是否创建pr + # create_new_pr(params) render_result(1, "更新成功") else render_error(interactor.error) @@ -90,7 +112,7 @@ class RepositoriesController < ApplicationController end def delete_file - interactor = Gitea::DeleteFileInteractor.call(current_user, params.merge(identifier: @project.identifier)) + interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier)) if interactor.success? @file = interactor.result render_result(1, "文件删除成功") @@ -104,10 +126,10 @@ class RepositoriesController < ApplicationController end def sync_mirror - return render_error("正在镜像中..") if @repo.mirror.waiting? + return render_error("正在镜像中..") if @repository.mirror.waiting? - @repo.sync_mirror! - SyncMirroredRepositoryJob.perform_later(@repo.id, current_user.id) + @repository.sync_mirror! + SyncMirroredRepositoryJob.perform_later(@repository.id, current_user.id) render_ok end @@ -123,6 +145,7 @@ class RepositoriesController < ApplicationController end def authorizate! + return if current_user && current_user.admin? if @project.repository.hidden? && !@project.member?(current_user) render_forbidden end @@ -135,18 +158,18 @@ class RepositoriesController < ApplicationController end def get_statistics - @branches_count = Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size - @tags_count = Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size + @branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size + @tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size end def get_ref @ref = params[:ref] || "master" end - def get_latest_commit - latest_commit = project_commits - @latest_commit = latest_commit[:body][0] if latest_commit.present? - @commits_count = latest_commit[:total_count] if latest_commit.present? + def get_latest_commit + latest_commit = @project.educoder? ? nil : project_commits + @latest_commit = latest_commit.present? ? latest_commit[:body][0] : nil + @commits_count = latest_commit.present? ? latest_commit[:total_count] : 0 end def content_params @@ -156,6 +179,10 @@ class RepositoriesController < ApplicationController new_branch: params[:new_branch], content: params[:content], message: params[:message], + committer: { + email: current_user.mail, + name: current_user.login + }, identifier: @project.identifier } end @@ -210,7 +237,7 @@ class RepositoriesController < ApplicationController issue_type: "1", tracker_id: 2, status_id: 1, - priority_id: 1 + priority_id: params[:priority_id] || "2" } @pull_issue = Issue.new(issue_params) if @pull_issue.save! diff --git a/app/controllers/sync_forge_controller.rb b/app/controllers/sync_forge_controller.rb index eb42f607..12a2cac4 100644 --- a/app/controllers/sync_forge_controller.rb +++ b/app/controllers/sync_forge_controller.rb @@ -1,288 +1,334 @@ class SyncForgeController < ApplicationController # before_action :check_token - def create - ActiveRecord::Base.transaction do - params.permit! - sync_params = params[:sync_params] - #以前已同步的项目,那么肯定存在仓库 - if Project.exists?(identifier: sync_params[:identifier]) - SyncLog.sync_log("=================begin_to_update_project========") - project = Project.find_by(identifier: sync_params[:identifier]) - check_sync_project(project, sync_params) - else #新建项目 - SyncLog.sync_log("=================begin_to_create_new_project========") - project_user = User.where(login: sync_params[:owner_login]).first - project_params = { - repository_name: sync_params[:identifier], - user_id: project_user.id, - private: !sync_params[:is_public], - name: sync_params[:name] - } - project = Projects::CreateService.new(project_user, project_params).call - if project.present? - if sync_params[:project_score].present? - sync_params.permit! - score_params = sync_params[:project_score].merge(project_id: project.id) - new_project_score = ProjectScore.create(score_params) - SyncLog.sync_log("=================new_project_score:#{new_project_score.try(:id)}========") - end - - SyncRepositoryJob.perform_later(sync_params[:owner_login], sync_params[:identifier], sync_params[:repository], get_sudomain) if sync_params[:repository].present? - check_new_project(project, sync_params) - end - end - end - rescue Exception => e - SyncLog.sync_project_log("=============sync_has_errors:==#{e.message}, project_id==:#{params[:sync_params][:id]}") - end - - def sync_users - params.permit! - sync_params = params[:sync_params] - users_params = sync_params[:users] - - users_params.each do |u| - if User.exists?(login: u[:user_params][:login]) - SyncLog.sync_log("=================sync_to_user_been_exists====#{u[:user_params][:login]}") - else - # new_user = User.new(u[:user_params]) - - if u[:user_params][:mail].blank? - u_mail = "#{u[:user_params][:login]}@example.com" - else - u_mail = u[:user_params][:mail] - end - - new_user = User.new(u[:user_params].merge(mail: u_mail)) - - username = new_user.login - password = "12345678" - if new_user.save! - SyncLog.sync_log("=================sync_to_user_success==#{new_user.login}") - else - SyncLog.sync_log("=================sync_to_user_failed,user_login==#{new_user.login}") - end - # ActiveRecord::Base.transaction do - # interactor = Gitea::RegisterInteractor.call({username: username, email: new_user.mail, password: password}) - # if interactor.success? - # gitea_user = interactor.result - # result = Gitea::User::GenerateTokenService.new(username, password).call - # new_user.gitea_token = result['sha1'] - # new_user.gitea_uid = gitea_user['id'] - # if new_user.save! - # UserExtension.create!(u[:user_extensions][:user_extensions].merge(user_id: new_user.id)) if u[:user_extensions].present? && u[:user_extensions][:user_extensions].present? - # else - # SyncLog.sync_log("=================sync_to_user_failed,user_login==#{new_user.login}") - # end - # else - # SyncLog.sync_project_log("=============sync_to_user_failed,user_login====#{new_user.login}") - # SyncLog.sync_log("=================sync_to_user_failed,user_login====#{new_user.login}") - # end - # end - end - end - # normal_status(1, "completed_sync") - rescue Exception => e - SyncLog.sync_log("=================sync_user_failed====#{e}") - end - - private - - def check_sync_project(project,sync_params) - begin - gitea_main = "https://www.trustie.net/" - if request.subdomain === 'testforgeplus' - gitea_main = "https://ucloudtest.trustie.net/" - end - - SyncLog.sync_log("----begin_to_check_sync_project----project_id:#{project.id}---------------") - change_project_score(project, sync_params[:project_score], sync_params[:repository]) if sync_params[:repository].present? #更新project_score - change_project_issues(project, sync_params[:issues],project.id, gitea_main) - change_project_members(project, sync_params[:members],gitea_main) - change_project_versions(project, sync_params[:project_versions],gitea_main) - change_project_watchers(project, sync_params[:project_watchers],gitea_main) - change_project_praises(project, sync_params[:praise_trends],gitea_main) - rescue => e - SyncLog.sync_log("=========check_sync_project_errors:#{e}===================") - end - - end - - def check_new_project(project,sync_params) - SyncLog.sync_log("***8. begin_to_sync_new_project---------------") - sync_projects_params = { - type: "Project", - ids: sync_params[:id], - token: get_token, - sync_params: sync_params, - new_project_id: project.id - } - - gitea_main = "https://www.trustie.net/" - if request.subdomain === 'testforgeplus' - gitea_main = "https://ucloudtest.trustie.net/" - end - SyncProjectsJob.perform_later(sync_projects_params, gitea_main) - SyncLog.sync_log("***8. end_to_sync_new_project---------------") - end - - def change_project_praises(project, praises,gitea_main) - SyncLog.sync_log("***6. begin_to_sync_parises---------------") - forge_praises_ids = project&.praise_treads&.select(:id)&.pluck(:id) - diff_target_ids = praises[:ids] - forge_praises_ids - if diff_target_ids.size > 0 - sync_projects_params = { - type: "PraiseTread", - ids: diff_target_ids, - token: get_token, - parent_id: project.id - } - SyncProjectsJob.perform_later(sync_projects_params,gitea_main) - - SyncLog.sync_log("***6. end_to_sync_parises---------------") + def sync_range_projects + sync_counts = params[:sync_count] || 10 + projects = Project.includes(:project_score, :repository) + .where(is_public: true) + .where.not(identifier: ["educoder","trustieforge", "gitlab", "rGDBbQmOK", "socialforge"]) + .joins(:project_score).order("project_scores.changeset_num desc").limit(sync_counts.to_i) + projects.each do | project | + SyncProjectMilitaryJob.perform_later(project, project.repository, project.project_score) end end - #检查repository和project_score - def change_project_score(project, project_scores, repository_params) - SyncLog.sync_log("***1. begin_to_sync_project_score---------------") - begin - pre_project_score = project.project_score - if pre_project_score.present? - change_num = 0 - project_scores.each do |k,v| - unless pre_project_score.send("#{k}") == v - change_num += 1 - pre_project_score[:"#{k}"] = v - end - if k == "changeset_num" && v.to_i > pre_project_score.changeset_num.to_i && repository_params[:url].present? - SyncRepositoryJob.perform_later(project.owner.try(:login), project.identifier, repository_params, get_sudomain) - end - end - pre_project_score.save! if change_num > 0 #如果 project_score有变化则更新 - else - ProjectScore.create!(project_scores.merge(project_id: project.id)) - end - SyncLog.sync_log("***1. end_to_sync_project_score---------------") - rescue Exception => e - SyncLog.sync_log("=========change_project_score_errors:#{e}===================") - end - end + # def create + # ActiveRecord::Base.transaction do + # params.permit! + # sync_params = params[:sync_params] + # project_user = User.where(login: sync_params[:owner_login])&.first + # #以前已同步的项目,那么肯定存在仓库 + # SyncLog.sync_log("=================begin_to_sync_forge: project_identifier: #{sync_params[:identifier]}========") + # user_projects = Project.where(user_id: project_user.id) + # if user_projects.where(id: sync_params[:id], identifier: sync_params[:identifier]).present? + # has_project = true + # project = user_projects.where(id: sync_params[:id], identifier: sync_params[:identifier])&.first + # elsif user_projects.where(id: sync_params[:id]).present? + # has_project = true + # project = user_projects.where(id: sync_params[:id])&.first + # elsif user_projects.where(identifier: sync_params[:identifier]).present? + # has_project = true + # project = user_projects.where(identifier: sync_params[:identifier])&.first + # else + # has_project = false + # end - def change_project_issues(project, old_issues_params,project_id, gitea_main) - SyncLog.sync_log("***2. begin_to_syncissues---------------") - begin - forge_issue_ids = project&.issues&.select(:id)&.pluck(:id) - sync_projects_params = {} - unless forge_issue_ids.size.to_i < old_issues_params[:count].to_i - forge_journal_ids = Journal.select([:id, :journalized_id, :journalized_type]).where(journalized_id: forge_issue_ids).pluck(:id) - diff_issue_ids = old_issues_params[:ids] - forge_issue_ids - - if diff_issue_ids.size == 0 #issue数量一样,判断评论是否有增减 - diff_journal_ids = old_issues_params[:journals][:ids] - forge_journal_ids - unless diff_journal_ids.size == 0 - sync_projects_params = { - type: "Journal", - ids: diff_journal_ids, - token: get_token, - parent_id: project_id - } - end - else - sync_projects_params = { - type: "Issue", - ids: diff_issue_ids, - token: get_token, - parent_id: project_id - } - end - end - - SyncProjectsJob.perform_later(sync_projects_params, gitea_main) if sync_projects_params.present? - SyncLog.sync_log("***2. end_to_syncissues---------------") - rescue Exception => e - SyncLog.sync_log("=========change_project_issues_errors:#{e}===================") - end - end + # if has_project + # SyncLog.sync_log("=================begin_to_update_project========") + # check_sync_project(project, sync_params) + # else #新建项目 + # SyncLog.sync_log("=================begin_to_create_new_project========") - def change_project_watchers(project, watchers,gitea_main) - SyncLog.sync_log("***5. begin_to_sync_watchers---------------") - forge_watchers_ids = project&.watchers&.select(:id)&.pluck(:id) - unless forge_watchers_ids.size.to_i < watchers[:count].to_i - diff_target_ids = watchers[:ids] - forge_watchers_ids - if diff_target_ids.size > 0 - sync_projects_params = { - type: "Watcher", - ids: diff_target_ids, - token: get_token, - parent_id: project.id - } - SyncProjectsJob.perform_later(sync_projects_params,gitea_main) - - end - end - SyncLog.sync_log("***5. begin_to_sync_watchers---------------") - end + # project_params = { + # repository_name: sync_params[:identifier], + # user_id: project_user.id, + # private: !sync_params[:is_public], + # name: sync_params[:name] + # } + # project = Projects::CreateService.new(project_user, project_params).call + # if project.present? + # if sync_params[:project_score].present? + # sync_params.permit! + # score_params = sync_params[:project_score].merge(project_id: project.id) + # new_project_score = ProjectScore.create(score_params) + # SyncLog.sync_log("=================new_project_score:#{new_project_score.try(:id)}========") + # end - def change_project_versions(project, versions,gitea_main) - SyncLog.sync_log("***4. begin_to_sync_versions---------------") - forge_version_ids = project&.versions&.select(:id)&.pluck(:id) - unless forge_version_ids.size < versions[:count].to_i - diff_version_ids = versions[:ids] - forge_version_ids - if diff_version_ids.size > 0 - sync_projects_params = { - type: "Version", - ids: diff_version_ids, - token: get_token, - parent_id: project.id - } - SyncProjectsJob.perform_later(sync_projects_params,gitea_main) - end - - SyncLog.sync_log("***4. end_to_sync_versions---------------") - end - end + # SyncRepositoryJob.perform_later(sync_params[:owner_login], sync_params[:identifier], sync_params[:repository], get_sudomain) if sync_params[:repository].present? + # check_new_project(project, sync_params) + # else + # SyncLog.sync_project_log("=============new_project_create_failed, trustie_project_id==:#{params[:sync_params][:id]}") + # end + # end + # end + # rescue Exception => e + # SyncLog.sync_project_log("=============sync_has_errors:==#{e.message}, project_id==:#{params[:sync_params][:id]}") + # end - def change_project_members(project, members,gitea_main) - SyncLog.sync_log("***3. begin_to_sync_members---------------") - forge_member_ids = project&.members&.select(:id)&.pluck(:id) - unless forge_member_ids.size < members[:count] - diff_member_ids = members[:ids] - forge_member_ids - if diff_member_ids.size > 0 - sync_projects_params = { - type: "Member", - ids: diff_member_ids, - token: get_token, - parent_id: project.id - } - SyncProjectsJob.perform_later(sync_projects_params,gitea_main) - end - - SyncLog.sync_log("***3. end_to_sync_members---------------") - end - end + # def sync_users + # params.permit! + # sync_params = params[:sync_params] + # users_params = sync_params[:users] - # def check_token + # users_params.each do |u| + # if User.exists?(login: u[:user_params][:login]) + # SyncLog.sync_log("=================sync_to_user_been_exists====#{u[:user_params][:login]}") + # else + # # new_user = User.new(u[:user_params]) + + # if u[:user_params][:mail].blank? + # u_mail = "#{u[:user_params][:login]}@example.com" + # else + # u_mail = u[:user_params][:mail] + # end + + # new_user = User.new(u[:user_params].merge(mail: u_mail)) + + # username = new_user.login + # password = "12345678" + # # if new_user.save! + # # SyncLog.sync_log("=================sync_to_user_success==#{new_user.login}") + # # else + # # SyncLog.sync_log("=================sync_to_user_failed,user_login==#{new_user.login}") + # # end + # ActiveRecord::Base.transaction do + # interactor = Gitea::RegisterInteractor.call({username: username, email: new_user.mail, password: password}) + # if interactor.success? + # gitea_user = interactor.result + # result = Gitea::User::GenerateTokenService.new(username, password).call + # new_user.gitea_token = result['sha1'] + # new_user.gitea_uid = gitea_user['id'] + # if new_user.save! + # UserExtension.create!(u[:user_extensions][:user_extensions].merge(user_id: new_user.id)) if u[:user_extensions].present? && u[:user_extensions][:user_extensions].present? + # else + # SyncLog.sync_log("=================sync_to_user_failed,user_login==#{new_user.login}") + # end + # else + # SyncLog.sync_log("=============sync_to_user_failed,user_login====#{new_user.login}") + # SyncLog.sync_log("=================sync_to_user_failed,user_login====#{new_user.login}") + # end + # end + # end + # end + # # normal_status(1, "completed_sync") + # rescue Exception => e + # SyncLog.sync_log("=================sync_user_failed====#{e}") + # end + + # private + + # def check_sync_project(project,sync_params) + # begin + # gitea_main = "https://www.trustie.net/" + # # if request.subdomain === 'testforgeplus' + # # gitea_main = "https://ucloudtest.trustie.net/" + # # end + + # SyncLog.sync_log("----begin_to_check_sync_project----project_id:#{project.id}---------------") + # change_project_score(project, sync_params[:project_score], sync_params[:repository]) if sync_params[:repository].present? #更新project_score + # change_project_issues(project, sync_params[:issues],project.id, gitea_main) + # change_project_members(project, sync_params[:members],gitea_main) + # change_project_versions(project, sync_params[:project_versions],gitea_main) + # change_project_watchers(project, sync_params[:project_watchers],gitea_main) + # change_project_praises(project, sync_params[:praise_trends],gitea_main) + # rescue => e + # SyncLog.sync_log("=========check_sync_project_errors:#{e}===================") + # end + + # end + + # def check_new_project(project,sync_params) + # SyncLog.sync_log("***8. begin_to_sync_new_project---------------") + # sync_projects_params = { + # type: "Project", + # ids: sync_params[:id], + # token: get_token, + # sync_params: sync_params, + # new_project_id: project.id + # } + + # gitea_main = "https://www.trustie.net/" + # # if request.subdomain === 'testforgeplus' + # # gitea_main = "https://ucloudtest.trustie.net/" + # # end + # SyncProjectsJob.perform_later(sync_projects_params, gitea_main) + # SyncLog.sync_log("***8. end_to_sync_new_project---------------") + # end + + # def change_project_praises(project, praises,gitea_main) + # SyncLog.sync_log("***6. begin_to_sync_parises---------------") + # forge_praises_ids = project&.praise_treads&.select(:id)&.pluck(:id) + # diff_target_ids = praises[:ids] - forge_praises_ids + # if diff_target_ids.size > 0 + # sync_projects_params = { + # type: "PraiseTread", + # ids: diff_target_ids, + # token: get_token, + # parent_id: project.id + # } + # SyncProjectsJob.perform_later(sync_projects_params,gitea_main) + + # SyncLog.sync_log("***6. end_to_sync_parises---------------") + # end + # end + + # #检查repository和project_score + # def change_project_score(project, project_scores, repository_params) + # SyncLog.sync_log("***1. begin_to_sync_project_score---------------") + # begin + # pre_project_score = project.project_score + # if pre_project_score.present? + # change_num = 0 + # project_scores.each do |k,v| + # unless pre_project_score.send("#{k}") == v + # change_num += 1 + # pre_project_score[:"#{k}"] = v + # end + # if k == "changeset_num" && v.to_i > pre_project_score.changeset_num.to_i && repository_params[:url].present? + # SyncRepositoryJob.perform_later(project.owner.try(:login), project.identifier, repository_params, get_sudomain) + # end + # end + # pre_project_score.save! if change_num > 0 #如果 project_score有变化则更新 + # else + # ProjectScore.create!(project_scores.merge(project_id: project.id)) + # end + # SyncLog.sync_log("***1. end_to_sync_project_score---------------") + # rescue Exception => e + # SyncLog.sync_log("=========change_project_score_errors:#{e}===================") + # end + # end + + # def change_project_issues(project, old_issues_params,project_id, gitea_main) + # SyncLog.sync_log("***2. begin_to_syncissues---------------") + # begin + # forge_issue_ids = project&.issues&.select(:id)&.pluck(:id) + # sync_projects_params = {} + # SyncLog.sync_log("***2--01. forge_issue_ids-#{forge_issue_ids.size.to_i}--------------") + # if forge_issue_ids.size.to_i <= old_issues_params[:count].to_i + # diff_issue_ids = old_issues_params[:ids] - forge_issue_ids + + # if diff_issue_ids.size == 0 #issue数量一样,判断评论是否有增减 + # forge_journal_ids = Journal.select([:id, :journalized_id, :journalized_type]).where(journalized_id: forge_issue_ids).pluck(:id) + # diff_journal_ids = old_issues_params[:journals][:ids] - forge_journal_ids + # unless diff_journal_ids.size == 0 + # sync_projects_params = { + # type: "Journal", + # ids: diff_journal_ids, + # token: get_token, + # parent_id: project_id + # } + # SyncLog.sync_log("***2--02. sync_projects_params-#{sync_projects_params}--------------") + # SyncProjectsJob.perform_later(sync_projects_params, gitea_main) + # end + # else + # new_diff_ids = diff_issue_ids.in_groups_of(200).map{|k| k.reject(&:blank?)} + # diff_len = new_diff_ids.length + # (1..diff_len).each do |len| + # sync_projects_params = { + # type: "Issue", + # ids: new_diff_ids[len-1], + # token: get_token, + # parent_id: project_id + # } + # SyncLog.sync_log("***2--030#{len}. sync_projects_params_groups-#{sync_projects_params}--------------") + # SyncProjectsJob.perform_later(sync_projects_params, gitea_main) + # end + # # sync_projects_params = { + # # type: "Issue", + # # ids: diff_issue_ids, + # # token: get_token, + # # parent_id: project_id + # # } + # # SyncLog.sync_log("***2--03. sync_projects_params_groups-#{sync_projects_params}--------------") + # # SyncProjectsJob.perform_later(sync_projects_params, gitea_main) + + # end + # end + + # # SyncProjectsJob.perform_later(sync_projects_params, gitea_main) if sync_projects_params.present? + # SyncLog.sync_log("***2. end_to_syncissues---------------") + # rescue Exception => e + # SyncLog.sync_log("=========change_project_issues_errors:#{e}===================") + # end + # end + + # def change_project_watchers(project, watchers,gitea_main) + # SyncLog.sync_log("***5. begin_to_sync_watchers---------------") + # forge_watchers_ids = project&.watchers&.select(:id)&.pluck(:id) + # if forge_watchers_ids.size.to_i <= watchers[:count].to_i + # diff_target_ids = watchers[:ids] - forge_watchers_ids + # if diff_target_ids.size > 0 + # sync_projects_params = { + # type: "Watcher", + # ids: diff_target_ids, + # token: get_token, + # parent_id: project.id + # } + # SyncProjectsJob.perform_later(sync_projects_params,gitea_main) + + # end + # end + # SyncLog.sync_log("***5. begin_to_sync_watchers---------------") + # end + + # def change_project_versions(project, versions,gitea_main) + # SyncLog.sync_log("***4. begin_to_sync_versions---------------") + # forge_version_ids = project&.versions&.select(:id)&.pluck(:id) + # if forge_version_ids.size <= versions[:count].to_i + # diff_version_ids = versions[:ids] - forge_version_ids + # if diff_version_ids.size > 0 + # sync_projects_params = { + # type: "Version", + # ids: diff_version_ids, + # token: get_token, + # parent_id: project.id + # } + # SyncProjectsJob.perform_later(sync_projects_params,gitea_main) + # end + + # SyncLog.sync_log("***4. end_to_sync_versions---------------") + # end + # end + + # def change_project_members(project, members,gitea_main) + # SyncLog.sync_log("***3. begin_to_sync_members---------------") + # forge_member_ids = project&.members&.select(:id)&.pluck(:id) + # if forge_member_ids.size <= members[:count] + # diff_member_ids = members[:ids] - forge_member_ids + # if diff_member_ids.size > 0 + # sync_projects_params = { + # type: "Member", + # ids: diff_member_ids, + # token: get_token, + # parent_id: project.id + # } + # SyncProjectsJob.perform_later(sync_projects_params,gitea_main) + # end + + # SyncLog.sync_log("***3. end_to_sync_members---------------") + # end + # end + + # def check_token # sync_params = params[:sync_params] # unless sync_params[:token] && sync_params[:token] == get_token # render json: {message: "token_errors"} # end # end - def get_token - "34c82f51e0b699d9d16d70fd6497c9b1e4821d6ea3e872558a6537a091076b8e" - end + # def get_token + # "34c82f51e0b699d9d16d70fd6497c9b1e4821d6ea3e872558a6537a091076b8e" + # end - def get_sudomain - SyncLog.sync_log("=================request.subdomain:#{request.subdomain}========") - gitea_main = "gitea.trustie.net" - if request.subdomain === 'testforgeplus' - gitea_main = "testgitea2.trustie.net" - # elsif request.subdomain === 'forgeplus' - # gitea_main = "gitea.trustie.net" - end - return gitea_main - end + # def get_sudomain + # SyncLog.sync_log("=================request.subdomain:#{request.subdomain}========") + # gitea_main = "gitea.trustie.net" + # if request.subdomain === 'testforgeplus' + # gitea_main = "testgitea2.trustie.net" + # # elsif request.subdomain === 'forgeplus' + # # gitea_main = "gitea.trustie.net" + # end + # return gitea_main + # end -end \ No newline at end of file +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d51d0b19..c0e2002d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,8 +1,11 @@ class UsersController < ApplicationController + include Ci::DbConnectable 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? } + skip_before_action :check_sign, only: [:attachment_show] def list @@ -149,32 +152,41 @@ class UsersController < ApplicationController def trustie_related_projects projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc") projects_json = [] + domain_url = EduSetting.get('host_name') + '/projects' if projects.present? projects.each do |p| + project_url = "/#{p.owner.login}/#{p.identifier}" pj = { id: p.id, name: p.name, is_public: p.is_public, updated_on: p.updated_on.strftime("%Y-%m-%d"), + status: p.status, + is_member: p.member?(current_user.try(:id)), owner: { name: p.owner.try(:show_real_name), login: p.owner.login }, members_count: p&.members.size, issues_count: p.issues_count - p.pull_requests_count, - commits_count: p&.project_score&.changeset_num.to_i + commits_count: p&.project_score&.changeset_num.to_i, + http_url: domain_url + project_url, + http_collaborator_url: domain_url + project_url + "/setting/collaborator", + http_issues_url: domain_url + project_url + "/issues", + http_commits_url: domain_url + project_url + "/commits", + project_score: p&.project_score.present? ? p&.project_score&.as_json(:except=>[:created_at, :updated_at]).merge!(commit_time: format_time(p&.project_score&.commit_time)) : {} } projects_json.push(pj) end end Rails.logger.info("==========projects_json========+########{projects_json}") - render json: { projects: projects_json } + render json: { projects: projects_json.present? ? projects_json : {} } end def trustie_projects user_id = User.select(:id, :login).where(login: params[:login])&.first&.id projects = Project.visible - + projects = projects.joins(:members).where(members: { user_id: user_id }) search = params[:search].to_s.strip diff --git a/app/controllers/version_releases_controller.rb b/app/controllers/version_releases_controller.rb index b28aef7c..5b045ad8 100644 --- a/app/controllers/version_releases_controller.rb +++ b/app/controllers/version_releases_controller.rb @@ -1,6 +1,6 @@ class VersionReleasesController < ApplicationController - before_action :find_project_with_id - before_action :set_user_and_project + before_action :load_repository + before_action :set_user before_action :require_login, except: [:index] before_action :find_version , only: [:edit, :update, :destroy] skip_after_action :user_trace_log, only: [:update] @@ -124,14 +124,8 @@ class VersionReleasesController < ApplicationController private - - def set_user_and_project - # @project = Project.find_by_id(params[:project_id]) - @repository = @project.repository #项目的仓库 - @user = @project.owner - unless @user.present? && @project.present? && @repository.present? - normal_status(-1, "仓库不存在") - end + def set_user + @user = @repository.user end def find_version @@ -141,18 +135,18 @@ class VersionReleasesController < ApplicationController end end - def releases_params + def releases_params { body: params[:body], draft: params[:draft] || false, name: params[:name], - prerelease: params[:prerelease], + prerelease: params[:prerelease] || false, tag_name: params[:tag_name], target_commitish: params[:target_commitish] || "master" #分支 } end - def create_attachments(attachment_ids, target) + def create_attachments(attachment_ids, target) attachment_ids.each do |id| attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) unless attachment.blank? diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb index 742d4831..5ec769e9 100644 --- a/app/controllers/versions_controller.rb +++ b/app/controllers/versions_controller.rb @@ -1,6 +1,6 @@ class VersionsController < ApplicationController before_action :require_login, except: [:index, :show] - before_action :find_project_with_id + before_action :load_repository before_action :check_issue_permission, except: [:show, :index] before_action :set_version, only: [:edit, :update, :destroy, :show,:update_status] @@ -166,4 +166,4 @@ class VersionsController < ApplicationController end end -end \ No newline at end of file +end diff --git a/app/forms/ci/create_cloud_account_form.rb b/app/forms/ci/create_cloud_account_form.rb new file mode 100644 index 00000000..7da78a05 --- /dev/null +++ b/app/forms/ci/create_cloud_account_form.rb @@ -0,0 +1,10 @@ +class Ci::CreateCloudAccountForm + include ActiveModel::Model + + attr_accessor :ip_num, :account, :secret + + # validates :project_id, :account, :secret, presence: true + validates :account, :secret, presence: true + validates :ip_num, presence: true, format: { with: CustomRegexp::IP, multiline: true, message: 'IP 地址格式不对' } + +end diff --git a/app/forms/oauth_educoder_form.rb b/app/forms/oauth_educoder_form.rb new file mode 100644 index 00000000..f8222cfa --- /dev/null +++ b/app/forms/oauth_educoder_form.rb @@ -0,0 +1,30 @@ +class OauthEducoderForm + include ActiveModel::Model + + attr_accessor :login, :token, :callback_url + + validates :login, presence: true + validates :token, presence: true + validates :callback_url, presence: true + + validate :check_callback_url! + validate :check_auth! + + def check_auth! + secret = OauthEducoder.config[:access_key_secret] + before_raw_pay_load = Digest::SHA1.hexdigest("#{login}#{secret}#{Time.now.to_i/60-1}") + now_raw_pay_load = Digest::SHA1.hexdigest("#{login}#{secret}#{Time.now.to_i/60}") + + if token != now_raw_pay_load && token != before_raw_pay_load + raise '你的请求无效值无效.' + end + end + + def check_callback_url! + request_host = URI.parse(callback_url).host + callback_url = OauthEducoder.config[:callback_url_host] + + raise 'callback_url参数无效.' if request_host != callback_url + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2dc8c897..1ac9a85b 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -436,4 +436,9 @@ module ApplicationHelper def find_user_by_login(login) User.find_by_login login end + + def render_base64_decoded(str) + return nil if str.blank? + Base64.decode64 str + end end diff --git a/app/helpers/ci/builds_helper.rb b/app/helpers/ci/builds_helper.rb new file mode 100644 index 00000000..c0e59106 --- /dev/null +++ b/app/helpers/ci/builds_helper.rb @@ -0,0 +1,11 @@ +module Ci::BuildsHelper + def format_utc_time(unix_time) + return nil if unix_time == 0 + Time.at(unix_time).strftime("%Y-%m-%d %H:%M") + end + + def render_duartion_time(end_time, start_time) + return nil if end_time == 0 || start_time == 0 + game_spend_time(end_time - start_time) + end +end diff --git a/app/helpers/ci/languages_helper.rb b/app/helpers/ci/languages_helper.rb new file mode 100644 index 00000000..dc4fa897 --- /dev/null +++ b/app/helpers/ci/languages_helper.rb @@ -0,0 +1,2 @@ +module Ci::LanguagesHelper +end diff --git a/app/helpers/compare_helper.rb b/app/helpers/compare_helper.rb new file mode 100644 index 00000000..d920da30 --- /dev/null +++ b/app/helpers/compare_helper.rb @@ -0,0 +1,2 @@ +module CompareHelper +end diff --git a/app/helpers/dev_ops_helper.rb b/app/helpers/dev_ops_helper.rb new file mode 100644 index 00000000..cb4d7e9b --- /dev/null +++ b/app/helpers/dev_ops_helper.rb @@ -0,0 +1,2 @@ +module DevOpsHelper +end diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb index e3fa623c..c0960271 100644 --- a/app/helpers/members_helper.rb +++ b/app/helpers/members_helper.rb @@ -1,2 +1,18 @@ module MembersHelper + def get_user_token(user_login,reponame) + query_params = { + type: "query", + chain_params: { + reponame: reponame, + username: user_login + } + } + response = Gitea::Chain::ChainGetService.new(query_params).call + + if response.status == 200 + return JSON.parse(response.body)["balance"].to_i + else + return 0 + end + end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index f5df048d..c00010b2 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -28,8 +28,10 @@ module ProjectsHelper (User.find_by_login identifier) || (User.find_by_mail identifier) end - def json_response(project) - repo = project.repository + def json_response(project, user) + # repo = project.repository + repo = Repository.includes(:mirror).select(:id, :mirror_url).find_by(project: project) + tmp_json = {} unless project.common? tmp_json = tmp_json.merge({ @@ -41,16 +43,48 @@ module ProjectsHelper end tmp_json = tmp_json.merge({ - identifier: project.identifier, + identifier: render_identifier(project), name: project.name, + platform: project.platform, id: project.id, + repo_id: repo.id, + open_devops: (user.blank? || user.is_a?(AnonymousUser)) ? false : project.open_devops?, type: project.numerical_for_project_type, - author: { - login: project.owner.login, - name: project.owner.real_name, - image_url: url_to_avatar(project.owner) - } + author: render_owner(project) }).compact + render json: tmp_json end + + def render_owner(project) + if project.educoder? + { + login: project.project_educoder.owner, + name: project.project_educoder.owner, + image_url: project.project_educoder.image_url + } + else + { + login: @owner.login, + name: @owner.real_name, + image_url: url_to_avatar(@owner) + } + end + end + + def render_identifier(project) + project.educoder? ? project.project_educoder&.repo_name&.split('/')[1] : project.identifier + end + + def render_author(project) + project.educoder? ? project.project_educoder&.repo_name&.split('/')[0] : project.owner.login + end + + def render_educoder_avatar_url(project_educoder) + [Rails.application.config_for(:configuration)['educoder']['cdn_url'], project_educoder&.image_url].join('/') + end + + def render_avatar_url(owner) + ['images', url_to_avatar(owner)].join('/') + end end diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 2b6d9d40..10ad1377 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -1,11 +1,17 @@ module RepositoriesHelper + def render_permission(user, project) + return "Admin" if user&.admin? + return "Owner" if user === project.owner + project.get_premission(user) + end + def render_decode64_content(str) return nil if str.blank? - Base64.decode64(str).force_encoding('UTF-8') + Base64.decode64(str).force_encoding("UTF-8") end def download_type(str) - default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb png jpg gif tif psd svg RData rdata) + default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb png jpg gif tif psd svg RData rdata doc docx mpp vsdx) default_type.include?(str&.downcase) end @@ -44,7 +50,7 @@ module RepositoriesHelper end if r_content.include?("?") new_r_content = r_content + "&raw=true" - else + else new_r_content = r_content + "?raw=true" end unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:") @@ -56,4 +62,14 @@ module RepositoriesHelper return content end + + # unix_time values for example: 1604382982 + def render_format_time_with_unix(unix_time) + Time.at(unix_time).strftime("%Y-%m-%d %H:%M") + end + + # date for example: 2020-11-01T19:57:27+08:00 + def render_format_time_with_date(date) + date.to_time.strftime("%Y-%m-%d %H:%M") + end end diff --git a/app/helpers/tag_chosen_helper.rb b/app/helpers/tag_chosen_helper.rb index 75be474f..afd51170 100644 --- a/app/helpers/tag_chosen_helper.rb +++ b/app/helpers/tag_chosen_helper.rb @@ -1,4 +1,143 @@ module TagChosenHelper + def get_associated_data(project) + issue_comment_users_array = [] + cost_time_array = [] + all_issues = [] + { + "assign_user": render_cache_collaborators(project), + "tracker": render_cache_trackers, + "issue_status": render_cache_issue_statuses, + "priority": render_cache_issue_priorities, + "issue_version": render_cache_milestones(project), + "start_date": "", + "due_date": "", + "joins_users": issue_comment_users_array, + "cost_time_users": cost_time_array, + # "total_cost_time": Time.at(all_cost_time).utc.strftime('%H h %M min %S s'), + # "be_depended_issues": be_depended_issues_array, + # "depended_issues":depended_issues_array, + # "estimated_hours": issue_info[7], + "done_ratio": render_complete_percentage, + "issue_tag": render_issue_tags(project), + "issue_type": render_issue_species, + "all_issues": all_issues + } + end + + def render_cache_trackers + cache_key = "all_trackers/#{Tracker.maximum('id')}" + + Rails.cache.fetch(cache_key) do + Tracker.select(:id, :name, :position).collect do |event| + { + id: event.id, + name: event.name, + position: event.position, + is_chosen: '0' + } + end + end + end + + def render_cache_issue_statuses + cache_key = "all_issue_statuses/#{IssueStatus.maximum('id')}" + + Rails.cache.fetch(cache_key) do + IssueStatus.select(:id, :name, :position).collect do |event| + { + id: event.id, + name: event.name, + position: event.position, + is_chosen: '0' + } + end + end + end + + def render_cache_issue_priorities + cache_key = "all_issue_priorities/#{IssuePriority.maximum('id')}" + + Rails.cache.fetch(cache_key) do + IssuePriority.select(:id, :name, :position).collect do |event| + { + id: event.id, + name: event.name, + position: event.position, + is_chosen: '0' + } + end + end + end + + def render_complete_percentage + completion_nums = %w(0 10 20 30 40 50 60 70 80 90 100) + completion_nums.collect do |event| + { + id: event.to_i, + name: event + "%", + is_chosen: '0' + } + end + end + + def render_issue_species + species = %W(普通 悬赏) + + species.collect do |event| + { + id: event.to_i + 1, + token: nil, + is_chosen: '0' + } + end + end + + def render_issue_tags(project) + # project.issue_tags.last&.cache_key + cache_key = "all_issue_tags/#{project.issue_tags.maximum('updated_at')}" + + Rails.cache.fetch(cache_key) do + project.issue_tags.select(:id, :name, :color).collect do |event| + { + id: event.id, + name: event.name, + color: event.color, + is_chosen: '0' + } + end + end + end + + def render_cache_milestones(project) + cache_key = "all_milestones/#{project.versions.maximum('updated_on')}" + + Rails.cache.fetch(cache_key) do + project.versions.select(:id, :name, :status).collect do |event| + { + id: event.id, + name: event.name, + status: event.status, + is_chosen: '0' + } + end + end + end + + def render_cache_collaborators(project) + cache_key = "all_collaborators/#{project.members.maximum('created_on')}" + + Rails.cache.fetch(cache_key) do + project.members.includes(:user).collect do |event| + { + id: event.user&.id, + name: event.user&.show_real_name, + avatar_url: url_to_avatar(event.user), + is_chosen: '0' + } + end + end + end + def issue_left_chosen(project,issue_id) issue_info = Array.new(11) @@ -205,4 +344,4 @@ module TagChosenHelper # be_depended_issues_array # end -end \ No newline at end of file +end diff --git a/app/interactors/gitea/create_file_interactor.rb b/app/interactors/gitea/create_file_interactor.rb index d8232379..acceeaa9 100644 --- a/app/interactors/gitea/create_file_interactor.rb +++ b/app/interactors/gitea/create_file_interactor.rb @@ -1,15 +1,16 @@ module Gitea class CreateFileInteractor - def self.call(user, params={}) - interactor = new(user, params) + def self.call(token, owner, params={}) + interactor = new(token, owner, params) interactor.run interactor end attr_reader :error, :result - def initialize(user, params) - @user = user + def initialize(token, owner, params) + @token = token + @owner = owner @params = params end @@ -23,7 +24,7 @@ module Gitea def run Contents::CreateForm.new(valid_params).validate! - response = Gitea::Repository::Entries::CreateService.new(user, @params[:identifier], @params[:filepath], file_params).call + response = Gitea::Repository::Entries::CreateService.new(token, owner, @params[:identifier], @params[:filepath], file_params).call render_result(response) rescue Exception => exception Rails.logger.info "Exception ===========> #{exception.message}" @@ -33,7 +34,7 @@ module Gitea private - attr_reader :params, :user + attr_reader :params, :owner, :token def fail!(error) @error = error @@ -57,6 +58,7 @@ module Gitea file_params = file_params.merge(new_branch: @params[:new_branch]) unless @params[:new_branch].blank? file_params = file_params.merge(content: Base64.encode64(@params[:content])) file_params = file_params.merge(message: @params[:message]) unless @params[:message].blank? + file_params = file_params.merge(committer: @params[:committer]) file_params end end diff --git a/app/interactors/gitea/delete_file_interactor.rb b/app/interactors/gitea/delete_file_interactor.rb index d68988d1..9a48c9e5 100644 --- a/app/interactors/gitea/delete_file_interactor.rb +++ b/app/interactors/gitea/delete_file_interactor.rb @@ -1,15 +1,16 @@ module Gitea class DeleteFileInteractor - def self.call(user, params={}) - interactor = new(user, params) + def self.call(token, owner, params={}) + interactor = new(token, owner, params) interactor.run interactor end attr_reader :error, :result - def initialize(user, params) - @user = user + def initialize(token, owner, params) + @token = token + @owner = owner @params = params end @@ -23,7 +24,7 @@ module Gitea def run Contents::DeleteForm.new(valid_params).validate! - response = Gitea::Repository::Entries::DeleteService.new(user, @params[:identifier], @params[:filepath], file_params).call + response = Gitea::Repository::Entries::DeleteService.new(token, owner, @params[:identifier], @params[:filepath], file_params).call render_result(response) rescue Exception => exception fail!(exception.message) @@ -31,7 +32,7 @@ module Gitea private - attr_reader :params, :user + attr_reader :params, :owner, :token def fail!(error) puts "[exception]: error" diff --git a/app/interactors/gitea/register_interactor.rb b/app/interactors/gitea/register_interactor.rb index 909a6791..d8dbc6ca 100644 --- a/app/interactors/gitea/register_interactor.rb +++ b/app/interactors/gitea/register_interactor.rb @@ -22,7 +22,7 @@ module Gitea def run Gitea::UserForm.new(params).validate! - response = Gitea::User::RegisterService.new(params).call + response = Gitea::User::RegisterService.call(params.merge(token: token)) render_result(response) rescue Exception => exception Rails.logger.info "Exception ===========> #{exception.message}" @@ -41,5 +41,12 @@ module Gitea def render_result(response) @result = response end + + def token + { + username: Gitea.gitea_config[:access_key_id], + password: Gitea.gitea_config[:access_key_secret] + } + end end end diff --git a/app/interactors/gitea/update_file_interactor.rb b/app/interactors/gitea/update_file_interactor.rb index af895d48..7dc0c017 100644 --- a/app/interactors/gitea/update_file_interactor.rb +++ b/app/interactors/gitea/update_file_interactor.rb @@ -1,15 +1,16 @@ module Gitea class UpdateFileInteractor - def self.call(user, params={}) - interactor = new(user, params) + def self.call(token, owner, params={}) + interactor = new(token, owner, params) interactor.run interactor end attr_reader :error, :result - def initialize(user, params) - @user = user + def initialize(token, owner, params) + @owner = owner + @token = token @params = params end @@ -23,7 +24,7 @@ module Gitea def run Contents::UpdateForm.new(valid_params).validate! - response = Gitea::Repository::Entries::UpdateService.new(user, @params[:identifier], @params[:filepath], file_params).call + response = Gitea::Repository::Entries::UpdateService.new(token, owner, @params[:identifier], @params[:filepath], file_params).call render_result(response) rescue Exception => exception fail!(exception.message) @@ -31,7 +32,7 @@ module Gitea private - attr_reader :params, :user + attr_reader :params, :owner, :token def fail!(error) puts "[exception]: error" diff --git a/app/jobs/broadcast_mirror_repo_msg_job.rb b/app/jobs/broadcast_mirror_repo_msg_job.rb new file mode 100644 index 00000000..6372ae2e --- /dev/null +++ b/app/jobs/broadcast_mirror_repo_msg_job.rb @@ -0,0 +1,29 @@ +class BroadcastMirrorRepoMsgJob < ApplicationJob + queue_as :default + + def perform(repo_id) + puts "############ BroadcastMirrorRepoMsgJob start ############ #{repo_id}" + repo = Repository.find_by(id: repo_id) + return if repo.blank? + + project = repo.project + + json_data = { + mirror_status: repo.mirror_status, + mirror_num: repo.mirror_num, + mirror_url: repo.mirror_url, + first_sync: repo.first_sync?, + identifier: repo.identifier, + name: project.name, + id: project.id, + type: project.numerical_for_project_type + } + puts "############ broadcast start.......... " + puts "############ broadcast channel_name: channel_room_#{project.id}" + puts "############ broadcast project data: #{json_data} " + + cable_result = ActionCable.server.broadcast "channel_room_#{project.id}", project: json_data + + puts "############ broadcast result: #{cable_result == 1 ? 'successed' : 'failed'} " + end +end diff --git a/app/jobs/check_mirror_job.rb b/app/jobs/check_mirror_job.rb new file mode 100644 index 00000000..9854110b --- /dev/null +++ b/app/jobs/check_mirror_job.rb @@ -0,0 +1,36 @@ + +# 运行示例: bundle exec rails runner "CheckMirrorJob.new.call()" + +class CheckMirrorJob < ApplicationJob + queue_as :default + + def perform(project) + SyncLog.sync_log("==========begin_check_project_id_job:#{project.id}============") + begin + response = Gitea::Repository::Branches::ListService.new(project.owner, project.identifier).call + unless response.present? + SyncLog.sync_log("==========check_project_error_id:#{project.id}============") + ActiveRecord::Base.transaction do + delete_gitea = Gitea::Repository::DeleteService.new(project.owner, project.identifier).call + if delete_gitea.status == 204 || delete_gitea.status == 404 #删除成功或者仓库不存在,都重新创建 + repository_params= { + name: project.identifier, + auto_init: true, + private: project.repository.hidden, + } + gitea_repository = Gitea::Repository::CreateService.new(project.owner.gitea_token, repository_params).call + if gitea_repository + project.update_columns(gpid: gitea_repository["id"],forked_count: gitea_repository["forks_count"]) + else + SyncLog.sync_log("==========gitea_repository_created_failed:#{project.id}============") + end + else + SyncLog.sync_log("==========delete_gitea_failed:#{project.id}============") + end + end + end + rescue => e + SyncLog.sync_log("==========failed_check_project_id:#{project.id}============errors:#{e}") + end + end +end \ No newline at end of file diff --git a/app/jobs/migrate_remote_repository_job.rb b/app/jobs/migrate_remote_repository_job.rb index 6180bf5d..03727908 100644 --- a/app/jobs/migrate_remote_repository_job.rb +++ b/app/jobs/migrate_remote_repository_job.rb @@ -10,24 +10,8 @@ class MigrateRemoteRepositoryJob < ApplicationJob gitea_repository = Gitea::Repository::MigrateService.new(token, params).call if gitea_repository repo&.project&.update_columns(gpid: gitea_repository["id"]) - repo&.mirror&.update_columns(status: Mirror.statuses[:succeeded]) - - project = repo.project - - json_data = { - mirror_status: repo.mirror_status, - mirror_num: repo.mirror_num, - mirror_url: repo.mirror_url, - first_sync: repo.first_sync?, - identifier: repo.identifier, - name: project.name, - id: project.id, - type: project.numerical_for_project_type - } - puts "############ broadcast start.......... ############" - cable_result = ActionCable.server.broadcast "channel_room_#{repo.identifier}", project: json_data - - puts "############ room_channel_#{repo.identifier} result : #{cable_result}" + repo&.mirror&.succeeded! + puts "############ mirror status: #{repo.mirror.status} ############" end end end diff --git a/app/jobs/post_chain_job.rb b/app/jobs/post_chain_job.rb new file mode 100644 index 00000000..68aefbae --- /dev/null +++ b/app/jobs/post_chain_job.rb @@ -0,0 +1,24 @@ +class PostChainJob < ApplicationJob + queue_as :default + + def perform(chain_params) + status = false + chain_type = chain_params[:type].to_s + reponame = chain_params[:chain_params][:reponame] + 5.times do |i| + if status + break + else + response = Gitea::Chain::ChainPostService.new(chain_params).call + if response.status == 200 + reponse_body = response&.body + messages = reponse_body.present? ? JSON.parse(reponse_body) : "success" + status = true + Rails.logger.info("################_repository__#{reponame}______create_chain_success_try:_#{i+1}_message__:#{messages}__") + else + Rails.logger.info("########_repository__#{reponame}______create_chain_failed__try:_#{i+1}_") + end + end + end + end +end \ No newline at end of file diff --git a/app/jobs/sync_educoder_shixun_job.rb b/app/jobs/sync_educoder_shixun_job.rb new file mode 100644 index 00000000..d5f78271 --- /dev/null +++ b/app/jobs/sync_educoder_shixun_job.rb @@ -0,0 +1,73 @@ +require 'uri' +require 'net/http' + +class SyncEducoderShixunJob < ApplicationJob + queue_as :default + + def perform(url, private_token, page, per_page) + uri = URI("#{url}?page=#{page}&per_page=#{per_page}&private_token=#{private_token}") + puts "-------url: #{uri}" + response = Net::HTTP.get_response(uri) + + result = JSON.parse(response.body) + + if result['status'] != 0 + puts "======= 接口请求失败!" + return + end + + result['data']['repositories'].each do |re| + next if re['repo_name'].blank? + next if ProjectEducoder.exists?(repo_name: re['repo_name']) + + language = ProjectLanguage.find_by_name re['language'] + language = ProjectLanguage.create!(name: re['language']) if language.blank? + + category = ProjectCategory.find_by_name re['category'] + category = ProjectCategory.create!(name: re['category']) if category.blank? + + project_params = + { + name: re['name'], + # user_id: params[:user_id], + description: re['description'], + project_category_id: category.id, + project_language_id: language.id, + is_public: true, + # ignore_id: params[:ignore_id], + # license_id: params[:license_id], + identifier: re['repo_name'], + platform: Project.platforms[:educoder] + } + + project = Project.new(project_params) + + ActiveRecord::Base.transaction do + if project.save! + repo_params = + { + hidden: false, + project_id: project.id, + identifier: re['repo_name'] + } + + ProjectEducoder.create!( + project_id: project.id, + owner: re['username'], + repo_name: re['repo_name'], + forked_count: re['forked_count'], + commit_count: re['commit_count'], + image_url: re['image_url']) + + repo = Repository.new(repo_params) + repo.save! + + puts "项目: #{re['name']} 同步成功" + else + puts "项目: #{re['name']} 同步失败" + end + end + end + end + +end diff --git a/app/jobs/sync_project_military_job.rb b/app/jobs/sync_project_military_job.rb new file mode 100644 index 00000000..8c52181e --- /dev/null +++ b/app/jobs/sync_project_military_job.rb @@ -0,0 +1,22 @@ +require 'uri' +require 'net/http' + +class SyncProjectMilitaryJob < ApplicationJob + queue_as :default + + def perform(project, repository, project_socre) + SyncLog.sync_log("============begin to sync project, project_id: #{project.id} ===========") + project_except_params = %w(id user_id praises_count watchers_count issues_count pull_requests_count versions_count issue_tags_count closed_issues_count forked_from_project_id forked_count) + project_params = { + project: project.as_json(except: project_except_params), + repository: repository.as_json(except: %w(id project_id login user_id)), + project_socre: project_socre.as_json(except: %w(id project_id)) + } + url = "http://39.105.176.215:49999/api/sync_forge/sync_projects" #trustie上的相关路由 + uri = URI.parse(url) + http = Net::HTTP.new(uri.hostname, uri.port) + http.use_ssl = false + response = http.send_request('POST', uri.path, project_params.to_json, {'Content-Type' => 'application/json'}) + SyncLog.sync_log("============end to sync project, status: #{response.code} ===========") + end +end diff --git a/app/jobs/sync_projects_job.rb b/app/jobs/sync_projects_job.rb index cfa52d22..4b8339d6 100644 --- a/app/jobs/sync_projects_job.rb +++ b/app/jobs/sync_projects_job.rb @@ -8,28 +8,28 @@ class SyncProjectsJob < ApplicationJob SyncLog.sync_log("==========begin to sync #{sync_params[:type]} to forge============") SyncLog.sync_log("==========sync_params:#{sync_params}============") - begin + begin url = "#{gitea_main}/sync_forges" #trustie上的相关路由 uri = URI.parse(url) http = Net::HTTP.new(uri.hostname, uri.port) http.use_ssl = true response = http.send_request('GET', uri.path, sync_params.to_json, {'Content-Type' => 'application/json'}) - SyncLog.sync_log("==========response_status::#{response.code}============") + SyncLog.sync_log("=======#{sync_params[:parent_id].present? ? sync_params[:parent_id] : sync_params[:new_project_id]}===response_status::#{response.code}============") if response.code == '200' target_jsons = eval(response.body) if sync_params[:type] == "Project" - SyncLog.sync_project_log("==========target_jsons: #{target_jsons}============") + # SyncLog.sync_log("==========target_jsons: #{target_jsons}============") update_new_project(target_jsons[:targets_params][0], sync_params[:new_project_id]) else - SyncLog.sync_project_log("========== #{sync_params[:type]}============") + SyncLog.sync_log("========== #{sync_params[:type]}============") create_target(target_jsons[:targets_params], sync_params[:type].to_s) end else - SyncLog.sync_project_log("==========sync_project_to_forge_failed #{sync_params[:type]}============") + SyncLog.sync_log("==========sync_project_to_forge_failed #{sync_params[:type]}============") end rescue => e - SyncLog.sync_project_log("==========sync_project_to_forge_failed #{sync_params[:type]}============errors:#{e}") + SyncLog.sync_log("==========sync_project_to_forge_failed #{sync_params[:type]}============errors:#{e}") end end @@ -39,41 +39,63 @@ class SyncProjectsJob < ApplicationJob SyncLog.sync_log("=========begin_to_update_project=project_id: #{project_id}============") project = Project.find_by(id: project_id) project.update(re[:target_params]) if re[:target_params].present? - create_target(re[:issues_params], "Issue") if re[:issues_params].present? create_target(re[:member_params], "Member") if re[:member_params].present? create_target(re[:watcher_params], "Watcher") if re[:watcher_params].present? create_target(re[:praise_treads], "PraiseTread") if re[:praise_treads].present? create_versions(project, re[:versions_params]) if re[:versions_params].present? + create_target(re[:issues_params], "Issue") if re[:issues_params].present? end def create_target(target_jsons, target_type) - begin - SyncLog.sync_project_log("***【#{target_type}】. begin_to_create_target---------------") - return SyncLog.sync_log("*** no target_jsons") if target_jsons.blank? - target_jsons.each_with_index do |re,index| - SyncLog.sync_project_log("***user_login:#{re[:user_login]}----target_type:#{target_type}-----#{index+1}") + SyncLog.sync_log("***【#{target_type}】. begin_to_create_target---------------") + return SyncLog.sync_log("*** no target_jsons") if target_jsons.blank? + target_jsons.each_with_index do |re,index| + begin + SyncLog.sync_log("***user_login:#{re[:user_login]}----target_type:#{target_type}-----#{index+1}") if re[:target_params].present? SyncLog.sync_log("***user_login:#{re[:user_login]}----target_type:#{target_type}") u_id = User.select(:id, :login).where(login: re[:user_login]).pluck(:id).first re[:target_params].delete(:id) if target_type == "Issue" - new_target = target_type.constantize.new(re[:target_params].merge(author_id: u_id)) + is_exists = Issue.exists?(author_id: u_id, project_id: re[:target_params][:project_id], subject: re[:target_params][:subject]) + unless is_exists + version_name = re[:re_version] + version_id = Version.where(project_id: re[:target_params][:project_id], name: version_name)&.first&.id if version_name.present? + assing_u_id = User.select(:id, :login).where(login: re[:assign_login]).pluck(:id).first + new_target = target_type.constantize.new(re[:target_params].merge(author_id: u_id)) + new_target.assigned_to_id = assing_u_id + new_target.fixed_version_id = version_id if version_id.present? + end else - new_target = target_type.constantize.new(re[:target_params].merge(user_id: u_id)) + case target_type + when "Journal" + is_exists = Journal.exists?(user_id: u_id, journalized_id: re[:target_params][:journalized_id], created_on: re[:target_params][:created_on].to_s.to_time) + when "Member" + is_exists = Member.exists?(user_id: u_id, project_id: re[:target_params][:project_id], created_on: re[:target_params][:created_on].to_s.to_time) + when "Version" + is_exists = Version.exists?(user_id: u_id, project_id: re[:target_params][:project_id], created_on: re[:target_params][:created_on].to_s.to_time) + when "Watcher" + is_exists = Watcher.exists?(user_id: u_id, watchable_id: re[:target_params][:watchable_id], created_at: re[:target_params][:created_at].to_s.to_time) + when "PraiseTread" + is_exists = PraiseTread.exists?(user_id: u_id, praise_tread_object_id: re[:target_params][:praise_tread_object_id], created_at: re[:target_params][:created_at].to_s.to_time) + else + is_exists = false + end + unless is_exists + new_target = target_type.constantize.new(re[:target_params].merge(user_id: u_id)) + end end - - if target_type == "Issue" - assing_u_id = User.select(:id, :login).where(login: re[:assign_login]).pluck(:id).first - new_target.assigned_to_id = assing_u_id - end - if new_target.save! - SyncLog.sync_project_log("***【#{target_type}】. create_success---------------") + + if !is_exists && new_target.save! + SyncLog.sync_log("***【#{target_type}】. create_success---------------") if re[:journals].present? create_journals(re[:journals], "Journal", new_target.id) end if re[:journal_details].present? re[:journal_details].each do |j| - JournalDetail.create!(j.merge(journal_id: new_target.id)) if j.present? + unless JournalDetail.exists?(journal_id: new_target.id) + JournalDetail.create!(j.merge(journal_id: new_target.id)) if j.present? + end end end if re[:member_roles].present? @@ -82,35 +104,51 @@ class SyncProjectsJob < ApplicationJob end end else - SyncLog.sync_project_log("***【#{target_type}】. create_failed---------------") + SyncLog.sync_log("***【#{target_type}】. create_failed---or has_exists---------------") end end + SyncLog.sync_log("***111222. end_to_create_target---------------") + rescue => e + SyncLog.sync_log("=========***【#{target_type}】creat_had_erros:#{e}===================") + next end - SyncLog.sync_project_log("***111222. end_to_create_target---------------") - rescue => e - SyncLog.sync_project_log("=========***【#{target_type}】creat_had_erros:#{e}===================") end - + end def create_journals(target_jsons, target_type,issue_id) SyncLog.sync_log("***【#{target_type}】. begin_to_create_target---------------") return SyncLog.sync_log("*** no target_jsons") if target_jsons.blank? target_jsons.each_with_index do |re,index| - SyncLog.sync_log("***user_login:#{re[:user_login]}----target_type:#{target_type}-----#{index+1}") - if re[:target_params].present? - u_id = User.select(:id, :login).where(login: re[:user_login]).pluck(:id).first - re[:target_params].delete(:id) - new_target = Journal.new(re[:target_params].merge(user_id: u_id)) - new_target.journalized_id = issue_id - if new_target.save! - if re[:journal_details].present? - re[:journal_details].each do |j| - JournalDetail.create!(j.merge(journal_id: new_target.id)) + begin + SyncLog.sync_log("***user_login:#{re[:user_login]}----target_type:#{target_type}-----#{index+1}") + if re[:target_params].present? + u_id = User.select(:id, :login).where(login: re[:user_login]).pluck(:id).first + is_exists = Journal.exists?(user_id: u_id, journalized_id: re[:target_params][:journalized_id], created_on: re[:target_params][:created_on].to_s.to_time) + + if is_exists + SyncLog.sync_log("***00000. Journal:#{re[:target_params][:id]}-is exists--------------") + else + re[:target_params].delete(:id) + new_target = Journal.new(re[:target_params].merge(user_id: u_id)) + new_target.journalized_id = issue_id + if new_target.save! + if re[:journal_details].present? + re[:journal_details].each do |j| + JournalDetail.create!(j.merge(journal_id: new_target.id)) + end + end + else + SyncLog.sync_log("***111222. journal_create failed---------------") + end end end + rescue => e + SyncLog.sync_log("***111222. journal_create failed---#{e}------------") + next end + end SyncLog.sync_log("***111222. end_to_create_journal---------------") end @@ -118,19 +156,27 @@ class SyncProjectsJob < ApplicationJob def create_versions(project, target_jsons) SyncLog.sync_log("***【Versions】. begin_to_create_verison---------------") return SyncLog.sync_log("*** no target_jsons") if target_jsons.blank? - all_issues = project.issues.select(:id, :project_id, :fixed_version_id) target_jsons.each do |re| old_id = re[:target_params][:id] if re[:target_params].present? u_id = User.select(:id, :login).where(login: re[:user_login]).pluck(:id).first - re[:target_params].delete(:id) - new_target = Version.new(re[:target_params].merge(user_id: u_id)) - if new_target.save! - all_issues&.where(fixed_version_id: old_id)&.update_all(fixed_version_id: new_target.id) + is_exists = Version.exists?(user_id: u_id, project_id: re[:target_params][:project_id], created_on: re[:target_params][:created_on].to_s.to_time) + if is_exists + SyncLog.sync_log("***00000. Version:#{re[:target_params][:id]}-is exists--------------") + else + re[:target_params].delete(:id) + new_target = Version.new(re[:target_params].merge(user_id: u_id)) + if new_target.save! + SyncLog.sync_log("***111222. Version_create success-#{new_target.id}--------------") + # all_issues = project.issues.select(:id, :project_id, :fixed_version_id) + # all_issues&.where(fixed_version_id: old_id)&.update_all(fixed_version_id: new_target.id) + else + SyncLog.sync_log("***111222. Version_create failed-#{old_id}--------------") + end end end end SyncLog.sync_log("***111222. end_to_create_target---------------") end -end \ No newline at end of file +end diff --git a/app/jobs/sync_repository_job.rb b/app/jobs/sync_repository_job.rb index c110ce15..9edbae98 100644 --- a/app/jobs/sync_repository_job.rb +++ b/app/jobs/sync_repository_job.rb @@ -25,13 +25,14 @@ class SyncRepositoryJob < ApplicationJob gitlab_branches.each do |branch| shell5 = system("cd #{path}/#{image_repo_name} && git checkout #{branch} && git push --force --set-upstream origin #{branch}") if !shell5 - SyncLog.sync_project_log("=============force_push_erros==#{path}/#{image_repo_name}++branch:#{branch}") + SyncLog.sync_log("=============force_push_erros==#{path}/#{image_repo_name}++branch:#{branch}") else - SyncLog.sync_project_log("=============force_push_success==#{path}/#{image_repo_name}++branch+++#{branch}") + SyncLog.sync_log("=============force_push_success==#{path}/#{image_repo_name}++branch+++#{branch}") + system("rm -rf #{path}/#{image_repo_name}") end end else - SyncLog.sync_project_log("=============check_clone_erros==#{path}/#{image_repo_name}") + SyncLog.sync_log("=============check_clone_erros==#{path}/#{image_repo_name}") SyncLog.sync_log("++++++++++++++++++check_clone_erros++++++++++++++++++#{image_repo_name}") end SyncLog.sync_log("=================end to sync repository=====================#{image_repo_name}") diff --git a/app/libs/ci/database.rb b/app/libs/ci/database.rb new file mode 100644 index 00000000..f3d606f4 --- /dev/null +++ b/app/libs/ci/database.rb @@ -0,0 +1,31 @@ +module Ci + class Database < ActiveRecord::Base + self.abstract_class = true + + # Dynamically sets the database connection. + def self.set_connection(params) + puts "[Ci::Database] set db connection params: #{params}" + establish_connection( + adapter: params[:adapter], + database: params[:database], + port: params[:port].to_i, + host: params[:host], + username: params[:username], + password: params[:password], + encoding: "utf8" + ) + end + + def self.get_connection_params(connect_to) + params = Hash.new + params[:adapter] = "mysql2" + params[:host] = connect_to[:host].to_s + params[:username] = connect_to[:username].to_s + params[:password] = connect_to[:password].to_s + params[:database] = connect_to[:database].to_s + params[:port] = connect_to[:port] || "43306" + params[:encoding] = "utf8" + return params + end + end +end diff --git a/app/libs/ci/drone/api.rb b/app/libs/ci/drone/api.rb new file mode 100644 index 00000000..6891efa9 --- /dev/null +++ b/app/libs/ci/drone/api.rb @@ -0,0 +1,81 @@ +class Ci::Drone::API < Ci::Drone::Request + 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, endpoint, owner, repo, options={}) + @drone_token = drone_token + @endpoint = endpoint + @owner = owner + @repo = repo + @options = options + end + + # Build List + # GET api/repos/{owner}/{name}/builds + # eq: + # Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier) + def builds + get(endpoint, "api/repos/#{owner}/#{repo}/builds", drone_token: drone_token) + end + + # Build Info + # GET api/repos/{owner}/{name}/builds/{number} + # eq: + # Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, project.owner.login, project.identifier, number: number).build + def build + get(endpoint, "api/repos/#{owner}/#{repo}/builds/#{options[:number]}", drone_token: drone_token) + end + + # Update .trustie-pipeline.yml file + # PATCH api/repos/{owner}/{name}\ + # eq: + # Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, project.owner.login, project.identifier, config_path: config_path).config_yml + def config_yml + 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: + # Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, project.owner.login, project.identifier).activate + def activate + 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: + # Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: number).restart + def restart + 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: + # Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: number).stop + def stop + 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: + # Ci::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 + + # Synchronize the currently authenticated user’s repository list. + # POST /api/user/repos + # eq: + # Ci::Drone::API.new(drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: number).sync + def sync_repos + post(endpoint, "/api/users/repos", drone_token: drone_token) + end +end diff --git a/app/libs/ci/drone/ci.rb b/app/libs/ci/drone/ci.rb new file mode 100644 index 00000000..c47b5396 --- /dev/null +++ b/app/libs/ci/drone/ci.rb @@ -0,0 +1,25 @@ +class Ci::Drone::Ci + attr_reader :host, :username, :password, :gitea_username + + # host: drone server's ip + # 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, current_user.login).get_token + def initialize(host, username, password, gitea_username) + @host = host + @username = username + @password = password + @gitea_username = gitea_username + end + + def get_token + puts "--------- sshpass -p #{password} ssh -o 'StrictHostKeyChecking no' #{username}@#{host} '#{cmd}'" + `sshpass -p #{password} ssh -o "StrictHostKeyChecking no" #{username}@#{host} "#{cmd}"` + end + + private + def cmd + "cd ..; cd var/lib/drone/; sqlite3 database.sqlite; .dump; select user_hash from users where user_login=#{gitea_username};" + end +end diff --git a/app/libs/ci/drone/client.rb b/app/libs/ci/drone/client.rb new file mode 100644 index 00000000..ebaef5b1 --- /dev/null +++ b/app/libs/ci/drone/client.rb @@ -0,0 +1,25 @@ +class Ci::Drone::Client + attr_reader :client_id, :drone_ip, :rpc_secret + + # client_id: user's client_id from oauth + # drone_ip: 云服务器IP地址, eq: 173.65.32.21 + # eq: + # DevOps::Drone::Client.new(current_user.oauth.client_id, 'drone_ip').generate_cmd + def initialize(client_id, drone_ip, rpc_secret) + @client_id = client_id + @drone_ip = drone_ip + @rpc_secret = rpc_secret + end + + def generate_cmd + "docker run -d \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e DRONE_RPC_HOST=#{drone_ip}:80 \ + -e DRONE_RPC_SECRET=#{rpc_secret} \ + -e DRONE_RUNNER_NAME=#{drone_ip} \ + --restart always \ + --name drone-agent--#{client_id} \ + --net='bridge' \ + drone/drone-runner-docker:1" + end +end diff --git a/app/libs/ci/drone/error.rb b/app/libs/ci/drone/error.rb new file mode 100644 index 00000000..2ddfccd8 --- /dev/null +++ b/app/libs/ci/drone/error.rb @@ -0,0 +1,14 @@ +class Ci::Drone::Error < StandardError + attr_reader :code + + def initialize(code, message) + super message + @code = code + end + + class << self + def parse(result) + new(result['errcode'], result['errmsg']) + end + end +end diff --git a/app/libs/ci/drone/request.rb b/app/libs/ci/drone/request.rb new file mode 100644 index 00000000..5f3e54be --- /dev/null +++ b/app/libs/ci/drone/request.rb @@ -0,0 +1,108 @@ +class Ci::Drone::Request + # Converts the response body to an ObjectifiedHash. + def self.parse(body) + body = decode(body) + + if body.is_a? Hash + ObjectifiedHash.new body + elsif body.is_a? Array + body.collect! { |e| ObjectifiedHash.new(e) } + elsif body == true + body + else + raise Error::Parsing.new "Couldn't parse a response body" + end + end + + # Decodes a JSON response into Ruby object. + def self.decode(response) + begin + JSON.load response + rescue JSON::ParserError + raise Error::Parsing.new "The response is not a valid JSON" + end + end + + def get(endpoint, path, options={}) + validate_request_params!(endpoint) + request(:get, endpoint, path, options) + end + + def post(endpoint, path, options={}) + validate_request_params!(endpoint) + request(:post, endpoint, path, options) + end + + def put(endpoint, path, options={}) + validate_request_params!(endpoint) + request(:put, endpoint, path, options) + end + + def patch(endpoint, path, options={}) + validate_request_params!(endpoint) + request(:patch, endpoint, path, options) + end + + def delete(endpoint, path, options={}) + validate_request_params!(endpoint) + request(:delete, endpoint, path, options) + end + + private + def request(method, endpoint, path, **params) + Rails.logger.info("[drone] request: #{method} #{path} #{params.except(:drone_token).inspect}") + + client ||= begin + Faraday.new(url: endpoint) do |req| + req.request :url_encoded + req.headers['Content-Type'] = 'application/json' + req.response :logger # 显示日志 + req.adapter Faraday.default_adapter + req.authorization :Bearer, params[:drone_token] + req.headers['Authorization'] + end + end + response = client.public_send(method, path) do |req| + req.body = params.except(:drone_token).to_json + end + + json_response(response) + 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 + + # Checks a base_uri and params for requests. + def validate_request_params!(endpoint) + raise "Please set an endpoint to API" unless endpoint + end + + def error_message(response) + "Server responded with code #{response.code}, message: #{response.parsed_response.message}. " \ + "Request URI: #{response.request.base_uri}#{response.request.path}" + end + + def json_response(response) + result = JSON.parse(response.body) + status = response.status + Rails.logger.info("[drone] response:#{status} #{result.inspect}") + + response.status != 200 ? result.merge!(status: response.status) : result + end +end diff --git a/app/libs/ci/drone/server.rb b/app/libs/ci/drone/server.rb new file mode 100644 index 00000000..add2e439 --- /dev/null +++ b/app/libs/ci/drone/server.rb @@ -0,0 +1,62 @@ +class Ci::Drone::Server + attr_reader :user_login, :client_id, :client_secret, :drone_host, :rpc_secret + + # client_id: user's client_id from oauth + # client_secret: user's client_id from oauth + # drone_host: 云服务器地址,eq: 173.53.21.31:80 + # eg: + # DevOps::Drone::Server.new(current_user.login, current_user.oauth.client_id, current_user.oauth.client_secret, 'drone_host').generate_cmd + def initialize(user_login, client_id, client_secret, drone_host, rpc_secret) + @user_login = user_login + @client_id = client_id + @drone_host = drone_host + @rpc_secret = rpc_secret + @client_secret = client_secret + end + + # TODO 一下代码方便测试,正式环境请移除 + # docker rm -f `docker ps -qa` + def generate_cmd + "service docker start; docker run \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e DRONE_DATABASE_DRIVER=mysql \ + -e DRONE_DATABASE_DATASOURCE=#{database_username}:'#{database_password}'@tcp\\(#{database_host}:#{database_port}\\)/#{user_login}_drone?parseTime=true \ + -e DRONE_GITEA_SERVER=#{gitea_url} \ + -e DRONE_GITEA_CLIENT_ID=#{client_id} \ + -e DRONE_GITEA_CLIENT_SECRET=#{client_secret} \ + -e DRONE_RPC_SECRET=#{rpc_secret} \ + -e DRONE_SERVER_HOST=#{drone_host} \ + -e DRONE_SERVER_PROTO=http \ + -p '80:80' \ + --restart=always \ + --detach=true \ + --name=drone-server-#{client_id} \ + --net='bridge' \ + drone/drone:1" + end + + private + def gitea_url + Gitea.gitea_config[:domain] + end + + def database_username + database_config[Rails.env]["ci_server_db"]["username"] + end + + def database_password + database_config[Rails.env]["ci_server_db"]["password"] + end + + def database_host + database_config[Rails.env]["ci_server_db"]["host"] + end + + def database_port + database_config[Rails.env]["ci_server_db"]["port"] || 3306 + end + + def database_config + Rails.configuration.database_configuration + end +end diff --git a/app/libs/ci/drone/start.rb b/app/libs/ci/drone/start.rb new file mode 100644 index 00000000..19b7d09c --- /dev/null +++ b/app/libs/ci/drone/start.rb @@ -0,0 +1,22 @@ +class Ci::Drone::Start + attr_reader :drone_username, :drone_password, :drone_host, :drone_server_cmd, :drone_client_cmd + + # drone_username="XXXX" 云服务器登录用户名 + # drone_password="XXXXX" 云服务器用户密码 + # drone_host="" 云服务器地址 + # eq: + # drone_server_cmd = DevOps::Drone::Server.new('client_id', 'client_secret', 'drone_url').generate_cmd + # drone_client_cmd = DevOps::Drone::Client.new('client_id', 'server_url').generate_cmd + # DevOps::Drone::Start.new(drone_username, drone_password, 'drone_host', drone_server_cmd, drone_client_cmd).run + def initialize(drone_username, drone_password, drone_host, drone_server_cmd, drone_client_cmd) + @drone_username = drone_username + @drone_password = drone_password + @drone_host = drone_host + @drone_server_cmd = drone_server_cmd + @drone_client_cmd = drone_client_cmd + end + + def run + `sshpass -p #{drone_password} ssh -o "StrictHostKeyChecking no" #{drone_username}@#{drone_host} "#{drone_server_cmd} && #{drone_client_cmd}"` + end +end diff --git a/app/libs/ci/schema.rb b/app/libs/ci/schema.rb new file mode 100644 index 00000000..b510f3a3 --- /dev/null +++ b/app/libs/ci/schema.rb @@ -0,0 +1,260 @@ +module Ci::Schema + class << self + def statement + sqls = <<-SQL + CREATE TABLE IF NOT EXISTS `repos` ( + `repo_id` int(11) NOT NULL AUTO_INCREMENT, + `repo_uid` varchar(250) DEFAULT NULL, + `repo_user_id` int(11) DEFAULT NULL, + `repo_namespace` varchar(250) DEFAULT NULL, + `repo_name` varchar(250) DEFAULT NULL, + `repo_slug` varchar(250) DEFAULT NULL, + `repo_scm` varchar(50) DEFAULT NULL, + `repo_clone_url` varchar(2000) DEFAULT NULL, + `repo_ssh_url` varchar(2000) DEFAULT NULL, + `repo_html_url` varchar(2000) DEFAULT NULL, + `repo_active` tinyint(1) DEFAULT NULL, + `repo_private` tinyint(1) DEFAULT NULL, + `repo_visibility` varchar(50) DEFAULT NULL, + `repo_branch` varchar(250) DEFAULT NULL, + `repo_counter` int(11) DEFAULT NULL, + `repo_config` varchar(500) DEFAULT NULL, + `repo_timeout` int(11) DEFAULT NULL, + `repo_trusted` tinyint(1) DEFAULT NULL, + `repo_protected` tinyint(1) DEFAULT NULL, + `repo_synced` int(11) DEFAULT NULL, + `repo_created` int(11) DEFAULT NULL, + `repo_updated` int(11) DEFAULT NULL, + `repo_version` int(11) DEFAULT NULL, + `repo_signer` varchar(50) DEFAULT NULL, + `repo_secret` varchar(50) DEFAULT NULL, + PRIMARY KEY (`repo_id`), + UNIQUE KEY `repo_slug` (`repo_slug`), + UNIQUE KEY `repo_uid` (`repo_uid`) + ) ENGINE=InnoDB AUTO_INCREMENT=137 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `builds` ( + `build_id` int(11) NOT NULL AUTO_INCREMENT, + `build_repo_id` int(11) DEFAULT NULL, + `build_config_id` int(11) DEFAULT NULL, + `build_trigger` varchar(250) DEFAULT NULL, + `build_number` int(11) DEFAULT NULL, + `build_parent` int(11) DEFAULT NULL, + `build_status` varchar(50) DEFAULT NULL, + `build_error` varchar(500) DEFAULT NULL, + `build_event` varchar(50) DEFAULT NULL, + `build_action` varchar(50) DEFAULT NULL, + `build_link` varchar(1000) DEFAULT NULL, + `build_timestamp` int(11) DEFAULT NULL, + `build_title` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `build_message` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `build_before` varchar(50) DEFAULT NULL, + `build_after` varchar(50) DEFAULT NULL, + `build_ref` varchar(500) DEFAULT NULL, + `build_source_repo` varchar(250) DEFAULT NULL, + `build_source` varchar(500) DEFAULT NULL, + `build_target` varchar(500) DEFAULT NULL, + `build_author` varchar(500) DEFAULT NULL, + `build_author_name` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `build_author_email` varchar(500) DEFAULT NULL, + `build_author_avatar` varchar(1000) DEFAULT NULL, + `build_sender` varchar(500) DEFAULT NULL, + `build_deploy` varchar(500) DEFAULT NULL, + `build_params` varchar(2000) DEFAULT NULL, + `build_started` int(11) DEFAULT NULL, + `build_finished` int(11) DEFAULT NULL, + `build_created` int(11) DEFAULT NULL, + `build_updated` int(11) DEFAULT NULL, + `build_version` int(11) DEFAULT NULL, + PRIMARY KEY (`build_id`), + UNIQUE KEY `build_repo_id` (`build_repo_id`,`build_number`) + ) ENGINE=InnoDB AUTO_INCREMENT=45 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `cron` ( + `cron_id` int(11) NOT NULL AUTO_INCREMENT, + `cron_repo_id` int(11) DEFAULT NULL, + `cron_name` varchar(50) DEFAULT NULL, + `cron_expr` varchar(50) DEFAULT NULL, + `cron_next` int(11) DEFAULT NULL, + `cron_prev` int(11) DEFAULT NULL, + `cron_event` varchar(50) DEFAULT NULL, + `cron_branch` varchar(250) DEFAULT NULL, + `cron_target` varchar(250) DEFAULT NULL, + `cron_disabled` tinyint(1) DEFAULT NULL, + `cron_created` int(11) DEFAULT NULL, + `cron_updated` int(11) DEFAULT NULL, + `cron_version` int(11) DEFAULT NULL, + PRIMARY KEY (`cron_id`), + UNIQUE KEY `cron_repo_id` (`cron_repo_id`,`cron_name`), + CONSTRAINT `cron_ibfk_1` FOREIGN KEY (`cron_repo_id`) REFERENCES `repos` (`repo_id`) ON DELETE CASCADE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + CREATE TABLE IF NOT EXISTS `latest` ( + `latest_repo_id` int(11) NOT NULL DEFAULT '0', + `latest_build_id` int(11) DEFAULT NULL, + `latest_type` varchar(50) NOT NULL DEFAULT '', + `latest_name` varchar(500) NOT NULL DEFAULT '', + `latest_created` int(11) DEFAULT NULL, + `latest_updated` int(11) DEFAULT NULL, + `latest_deleted` int(11) DEFAULT NULL, + PRIMARY KEY (`latest_repo_id`,`latest_type`,`latest_name`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `logs` ( + `log_id` int(11) NOT NULL, + `log_data` mediumblob, + PRIMARY KEY (`log_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `migrations` ( + `name` varchar(255) DEFAULT NULL, + UNIQUE KEY `name` (`name`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + CREATE TABLE IF NOT EXISTS `nodes` ( + `node_id` int(11) NOT NULL AUTO_INCREMENT, + `node_uid` varchar(500) DEFAULT NULL, + `node_provider` varchar(50) DEFAULT NULL, + `node_state` varchar(50) DEFAULT NULL, + `node_name` varchar(50) DEFAULT NULL, + `node_image` varchar(500) DEFAULT NULL, + `node_region` varchar(100) DEFAULT NULL, + `node_size` varchar(100) DEFAULT NULL, + `node_os` varchar(50) DEFAULT NULL, + `node_arch` varchar(50) DEFAULT NULL, + `node_kernel` varchar(50) DEFAULT NULL, + `node_variant` varchar(50) DEFAULT NULL, + `node_address` varchar(500) DEFAULT NULL, + `node_capacity` int(11) DEFAULT NULL, + `node_filter` varchar(2000) DEFAULT NULL, + `node_labels` varchar(2000) DEFAULT NULL, + `node_error` varchar(2000) DEFAULT NULL, + `node_ca_key` blob, + `node_ca_cert` blob, + `node_tls_key` blob, + `node_tls_cert` blob, + `node_tls_name` varchar(500) DEFAULT NULL, + `node_paused` tinyint(1) DEFAULT NULL, + `node_protected` tinyint(1) DEFAULT NULL, + `node_created` int(11) DEFAULT NULL, + `node_updated` int(11) DEFAULT NULL, + `node_pulled` int(11) DEFAULT NULL, + PRIMARY KEY (`node_id`), + UNIQUE KEY `node_name` (`node_name`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `orgsecrets` ( + `secret_id` int(11) NOT NULL AUTO_INCREMENT, + `secret_namespace` varchar(50) DEFAULT NULL, + `secret_name` varchar(200) DEFAULT NULL, + `secret_type` varchar(50) DEFAULT NULL, + `secret_data` blob, + `secret_pull_request` tinyint(1) DEFAULT NULL, + `secret_pull_request_push` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`secret_id`), + UNIQUE KEY `secret_namespace` (`secret_namespace`,`secret_name`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `perms` ( + `perm_user_id` int(11) NOT NULL DEFAULT '0', + `perm_repo_uid` varchar(250) NOT NULL DEFAULT '', + `perm_read` tinyint(1) DEFAULT NULL, + `perm_write` tinyint(1) DEFAULT NULL, + `perm_admin` tinyint(1) DEFAULT NULL, + `perm_synced` int(11) DEFAULT NULL, + `perm_created` int(11) DEFAULT NULL, + `perm_updated` int(11) DEFAULT NULL, + PRIMARY KEY (`perm_user_id`,`perm_repo_uid`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `secrets` ( + `secret_id` int(11) NOT NULL AUTO_INCREMENT, + `secret_repo_id` int(11) DEFAULT NULL, + `secret_name` varchar(500) DEFAULT NULL, + `secret_data` blob, + `secret_pull_request` tinyint(1) DEFAULT NULL, + `secret_pull_request_push` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`secret_id`), + UNIQUE KEY `secret_repo_id` (`secret_repo_id`,`secret_name`), + CONSTRAINT `secrets_ibfk_1` FOREIGN KEY (`secret_repo_id`) REFERENCES `repos` (`repo_id`) ON DELETE CASCADE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `stages` ( + `stage_id` int(11) NOT NULL AUTO_INCREMENT, + `stage_repo_id` int(11) DEFAULT NULL, + `stage_build_id` int(11) DEFAULT NULL, + `stage_number` int(11) DEFAULT NULL, + `stage_name` varchar(100) DEFAULT NULL, + `stage_kind` varchar(50) DEFAULT NULL, + `stage_type` varchar(50) DEFAULT NULL, + `stage_status` varchar(50) DEFAULT NULL, + `stage_error` varchar(500) DEFAULT NULL, + `stage_errignore` tinyint(1) DEFAULT NULL, + `stage_exit_code` int(11) DEFAULT NULL, + `stage_limit` int(11) DEFAULT NULL, + `stage_os` varchar(50) DEFAULT NULL, + `stage_arch` varchar(50) DEFAULT NULL, + `stage_variant` varchar(10) DEFAULT NULL, + `stage_kernel` varchar(50) DEFAULT NULL, + `stage_machine` varchar(500) DEFAULT NULL, + `stage_started` int(11) DEFAULT NULL, + `stage_stopped` int(11) DEFAULT NULL, + `stage_created` int(11) DEFAULT NULL, + `stage_updated` int(11) DEFAULT NULL, + `stage_version` int(11) DEFAULT NULL, + `stage_on_success` tinyint(1) DEFAULT NULL, + `stage_on_failure` tinyint(1) DEFAULT NULL, + `stage_depends_on` text, + `stage_labels` text, + PRIMARY KEY (`stage_id`), + UNIQUE KEY `stage_build_id` (`stage_build_id`,`stage_number`) + ) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `stages_unfinished` ( + `stage_id` int(11) NOT NULL, + PRIMARY KEY (`stage_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `steps` ( + `step_id` int(11) NOT NULL AUTO_INCREMENT, + `step_stage_id` int(11) DEFAULT NULL, + `step_number` int(11) DEFAULT NULL, + `step_name` varchar(100) DEFAULT NULL, + `step_status` varchar(50) DEFAULT NULL, + `step_error` varchar(500) DEFAULT NULL, + `step_errignore` tinyint(1) DEFAULT NULL, + `step_exit_code` int(11) DEFAULT NULL, + `step_started` int(11) DEFAULT NULL, + `step_stopped` int(11) DEFAULT NULL, + `step_version` int(11) DEFAULT NULL, + PRIMARY KEY (`step_id`), + UNIQUE KEY `step_stage_id` (`step_stage_id`,`step_number`) + ) ENGINE=InnoDB AUTO_INCREMENT=83 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + CREATE TABLE IF NOT EXISTS `users` ( + `user_id` int(11) NOT NULL AUTO_INCREMENT, + `user_login` varchar(250) DEFAULT NULL, + `user_email` varchar(500) DEFAULT NULL, + `user_admin` tinyint(1) DEFAULT NULL, + `user_machine` tinyint(1) DEFAULT NULL, + `user_active` tinyint(1) DEFAULT NULL, + `user_avatar` varchar(2000) DEFAULT NULL, + `user_syncing` tinyint(1) DEFAULT NULL, + `user_synced` int(11) DEFAULT NULL, + `user_created` int(11) DEFAULT NULL, + `user_updated` int(11) DEFAULT NULL, + `user_last_login` int(11) DEFAULT NULL, + `user_oauth_token` varchar(500) DEFAULT NULL, + `user_oauth_refresh` varchar(500) DEFAULT NULL, + `user_oauth_expiry` int(11) DEFAULT NULL, + `user_hash` varchar(500) DEFAULT NULL, + PRIMARY KEY (`user_id`), + UNIQUE KEY `user_login` (`user_login`), + UNIQUE KEY `user_hash` (`user_hash`) + ) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + SQL + + sqls + end + end +end diff --git a/app/libs/custom_regexp.rb b/app/libs/custom_regexp.rb index 497c26ca..4aa6fac2 100644 --- a/app/libs/custom_regexp.rb +++ b/app/libs/custom_regexp.rb @@ -5,4 +5,5 @@ module CustomRegexp NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/ PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/ URL = /\Ahttps?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]\z/ -end \ No newline at end of file + IP = /^((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/ +end diff --git a/app/libs/gitea/database.rb b/app/libs/gitea/database.rb new file mode 100644 index 00000000..4698607a --- /dev/null +++ b/app/libs/gitea/database.rb @@ -0,0 +1,12 @@ +module Gitea + class Database < ActiveRecord::Base + self.abstract_class = true + + def self.set_connection + gitea_server_config = Rails.configuration.database_configuration[Rails.env]["gitea_server"] + raise 'gitea database config missing' if gitea_server_config.blank? + + establish_connection gitea_server_config + end + end +end diff --git a/app/libs/oauth_educoder.rb b/app/libs/oauth_educoder.rb new file mode 100644 index 00000000..2d18b03a --- /dev/null +++ b/app/libs/oauth_educoder.rb @@ -0,0 +1,20 @@ +module OauthEducoder + class << self + def config + educoder_config = {} + + begin + config = Rails.application.config_for(:configuration).symbolize_keys! + educoder_config = config[:oauth_educoder].symbolize_keys! + raise 'oauth educoder config missing' if educoder_config.blank? + rescue => ex + raise ex if Rails.env.production? + + puts %Q{\033[33m [warning] educoder config or configuration.yml missing, + please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} + educoder_config = {} + end + educoder_config + end + end +end diff --git a/app/models/applied_message.rb b/app/models/applied_message.rb index ed02a544..8098e6e0 100644 --- a/app/models/applied_message.rb +++ b/app/models/applied_message.rb @@ -1,5 +1,23 @@ +# == Schema Information +# +# Table name: applied_messages +# +# id :integer not null, primary key +# user_id :integer +# applied_id :integer +# applied_type :string(255) +# viewed :integer default("0") +# status :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# name :string(255) +# applied_user_id :integer +# role :integer +# project_id :integer +# + class AppliedMessage < ApplicationRecord belongs_to :user belongs_to :applied, polymorphic: true -end \ No newline at end of file +end diff --git a/app/models/applied_project.rb b/app/models/applied_project.rb index 901443e8..68095d0e 100644 --- a/app/models/applied_project.rb +++ b/app/models/applied_project.rb @@ -1,3 +1,14 @@ +# == Schema Information +# +# Table name: applied_projects +# +# id :integer not null, primary key +# project_id :integer not null +# user_id :integer not null +# role :integer default("0") +# status :integer default("0") +# + class AppliedProject < ApplicationRecord belongs_to :user belongs_to :project diff --git a/app/models/apply_action.rb b/app/models/apply_action.rb index 53fc8d4c..02a14211 100644 --- a/app/models/apply_action.rb +++ b/app/models/apply_action.rb @@ -1,3 +1,26 @@ +# == Schema Information +# +# Table name: apply_actions +# +# id :integer not null, primary key +# user_id :integer +# reason :string(255) +# container_id :integer +# container_type :string(255) +# dealer_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# status :integer default("0") +# apply_reason :text(65535) +# noticed :boolean default("0") +# ip_addr :string(255) +# reject_description :string(255) +# +# Indexes +# +# index_apply_actions_on_user_id (user_id) +# + # 申请消息 class ApplyAction < ApplicationRecord belongs_to :user @@ -27,4 +50,4 @@ class ApplyAction < ApplicationRecord belong_container_id: container_id, belong_container_type: belong_container_type) end end -end \ No newline at end of file +end diff --git a/app/models/apply_user_authentication.rb b/app/models/apply_user_authentication.rb index ad74b026..10522a94 100644 --- a/app/models/apply_user_authentication.rb +++ b/app/models/apply_user_authentication.rb @@ -1,3 +1,23 @@ +# == Schema Information +# +# Table name: apply_user_authentications +# +# id :integer not null, primary key +# user_id :integer +# status :integer +# auth_type :integer +# remarks :string(255) +# dealer :integer +# deal_time :datetime +# created_at :datetime not null +# updated_at :datetime not null +# is_delete :boolean default("0") +# +# Indexes +# +# index_apply_user_authentications_on_user_id (user_id) +# + # status:0 审核中 1 同意 2 拒绝 3 撤销 # auth_type:1 实名认证, 2 职业认证 class ApplyUserAuthentication < ApplicationRecord diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 4057e7b9..9368d2d7 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -1,3 +1,36 @@ +# == Schema Information +# +# Table name: attachments +# +# id :integer not null, primary key +# container_id :integer +# container_type :string(30) +# filename :string(255) default(""), not null +# disk_filename :string(255) default(""), not null +# filesize :integer default("0"), not null +# content_type :string(255) default("") +# digest :string(40) default(""), not null +# downloads :integer default("0"), not null +# author_id :integer default("0"), not null +# created_on :datetime +# description :text(65535) +# disk_directory :string(255) +# attachtype :integer default("1") +# is_public :integer default("1") +# copy_from :integer +# quotes :integer +# is_publish :integer default("1") +# publish_time :datetime +# memo_image :boolean default("0") +# extra_type :integer default("0") +# +# Indexes +# +# index_attachments_on_author_id (author_id) +# index_attachments_on_container_id_and_container_type (container_id,container_type) +# index_attachments_on_created_on (created_on) +# + class Attachment < ApplicationRecord include BaseModel include Publicable diff --git a/app/models/attachment_group_setting.rb b/app/models/attachment_group_setting.rb index b7eb707f..3eaecf2b 100644 --- a/app/models/attachment_group_setting.rb +++ b/app/models/attachment_group_setting.rb @@ -1,3 +1,22 @@ +# == Schema Information +# +# Table name: attachment_group_settings +# +# id :integer not null, primary key +# attachment_id :integer +# course_group_id :integer +# course_id :integer +# publish_time :datetime +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_attachment_group_settings_on_attachment_id (attachment_id) +# index_attachment_group_settings_on_course_group_id (course_group_id) +# index_attachment_group_settings_on_course_id (course_id) +# + class AttachmentGroupSetting < ActiveRecord::Base belongs_to :attachment # belongs_to :course_group diff --git a/app/models/attachment_history.rb b/app/models/attachment_history.rb index c19146b9..86b672de 100644 --- a/app/models/attachment_history.rb +++ b/app/models/attachment_history.rb @@ -1,3 +1,31 @@ +# == Schema Information +# +# Table name: attachment_histories +# +# id :integer not null, primary key +# container_id :integer +# container_type :string(255) +# filename :string(255) default("") +# disk_filename :string(255) default("") +# filesize :integer default("0") +# content_type :string(255) default("") +# digest :string(60) default("") +# downloads :integer default("0") +# author_id :integer +# created_on :datetime +# description :text(65535) +# disk_directory :string(255) +# attachtype :integer +# is_public :integer +# copy_from :integer +# quotes :integer +# version :integer +# attachment_id :integer +# is_publish :integer default("1") +# publish_time :date +# cloud_url :string(255) default("") +# + class AttachmentHistory < ApplicationRecord include Publishable include Publicable diff --git a/app/models/bidding_user.rb b/app/models/bidding_user.rb index 3a427a01..9609e9e6 100644 --- a/app/models/bidding_user.rb +++ b/app/models/bidding_user.rb @@ -1,3 +1,20 @@ +# == Schema Information +# +# Table name: bidding_users +# +# id :integer not null, primary key +# project_package_id :integer +# user_id :integer +# status :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_bidding_users_on_project_package_id (project_package_id) +# index_bidding_users_on_user_id (user_id) +# + class BiddingUser < ApplicationRecord include AASM @@ -21,4 +38,4 @@ class BiddingUser < ApplicationRecord def status_text I18n.t("bidding_user.status.#{status}") end -end \ No newline at end of file +end diff --git a/app/models/ci.rb b/app/models/ci.rb new file mode 100644 index 00000000..2bce3b85 --- /dev/null +++ b/app/models/ci.rb @@ -0,0 +1,5 @@ +module Ci + # def self.table_name_prefix + # 'ci_' + # end +end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb new file mode 100644 index 00000000..6873f2ed --- /dev/null +++ b/app/models/ci/build.rb @@ -0,0 +1,14 @@ +class Ci::Build < Ci::RemoteBase + self.primary_key = 'build_id' + + belongs_to :repo, foreign_key: :build_repo_id + has_many :stages, foreign_key: "stage_build_id", dependent: :destroy + + scope :successed, ->{ by_status('success') } + scope :failed, -> { by_status('failure') } + scope :running, -> { by_status('running') } + scope :errored, -> { by_status('error') } + scope :pending, -> { by_status('pending') } + scope :killed, -> { by_status('killed') } + scope :by_status, ->(status) { where(build_status: status) } +end diff --git a/app/models/ci/cloud_account.rb b/app/models/ci/cloud_account.rb new file mode 100644 index 00000000..253017dc --- /dev/null +++ b/app/models/ci/cloud_account.rb @@ -0,0 +1,47 @@ +# == Schema Information +# +# Table name: ci_cloud_accounts +# +# id :integer not null, primary key +# user_id :integer not null +# ip_num :integer +# account :string(255) +# secret :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# ci_user_id :integer +# +# Indexes +# +# dev_ops_cloud_accounts_p_u_ip (user_id,ip_num) +# + +class Ci::CloudAccount < Ci::LocalBase + belongs_to :user + belongs_to :ci_user, class_name: 'Ci::User', foreign_key: :ci_user_id, optional: true + + def drone_host + [drone_ip, ":80"].join + end + + def drone_ip + IPAddr.new(self.ip_num, Socket::AF_INET).to_s + end + + def drone_url + ["http://", self.drone_host].join + end + + def visible_secret + Base64.decode64(secret) + end + + def self.encrypted_secret(str) + Base64.encode64(str.strip).gsub(/\n/, '') + end + + def authenticate_url + [drone_url, '/login'].join + end + +end diff --git a/app/models/ci/language.rb b/app/models/ci/language.rb new file mode 100644 index 00000000..3db42f35 --- /dev/null +++ b/app/models/ci/language.rb @@ -0,0 +1,28 @@ +# == Schema Information +# +# Table name: ci_languages +# +# id :integer not null, primary key +# name :string(255) not null +# content :text(65535) not null +# usage_amount :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# cover_id :integer +# + +class Ci::Language < Ci::LocalBase + # before_save :encode_content + + belongs_to :cover, class_name: "Attachment", foreign_key: :cover_id, optional: true + + scope :six_common, -> { limit(6).by_usage_amount_desc } + scope :without_content, -> { select(column_names - ['content']) } + scope :by_usage_amount_desc, -> { order(usage_amount: :desc) } + + + private + def encode_content + self.content = Base64.encode64 content + end +end diff --git a/app/models/ci/local_base.rb b/app/models/ci/local_base.rb new file mode 100644 index 00000000..2d6bf70f --- /dev/null +++ b/app/models/ci/local_base.rb @@ -0,0 +1,7 @@ +class Ci::LocalBase < ApplicationRecord + self.abstract_class = true + + def self.table_name_prefix + "ci_" + end +end diff --git a/app/models/ci/log.rb b/app/models/ci/log.rb new file mode 100644 index 00000000..b0c8e337 --- /dev/null +++ b/app/models/ci/log.rb @@ -0,0 +1,5 @@ +class Ci::Log < Ci::RemoteBase + self.primary_key = nil + + belongs_to :step, class_name: 'Ci::Step', foreign_key: :log_id +end diff --git a/app/models/ci/perm.rb b/app/models/ci/perm.rb new file mode 100644 index 00000000..e6bc2ebb --- /dev/null +++ b/app/models/ci/perm.rb @@ -0,0 +1,20 @@ +class Ci::Perm < Ci::RemoteBase + self.primary_key = nil + + belongs_to :user, class_name: 'Ci::User', foreign_key: :perm_user_id + belongs_to :repo, class_name: 'Ci::Repo', foreign_key: :perm_repo_uid + + def self.auto_create!(user, repo) + perm = new( + perm_user_id: user.user_id, + perm_repo_uid: repo.repo_id, + perm_read: true, + perm_write: true, + perm_admin: true, + perm_synced: 0, + perm_created: Time.now.to_i, + perm_updated: Time.now.to_i + ) + perm.save! + end +end diff --git a/app/models/ci/remote_base.rb b/app/models/ci/remote_base.rb new file mode 100644 index 00000000..836315ff --- /dev/null +++ b/app/models/ci/remote_base.rb @@ -0,0 +1,8 @@ +class Ci::RemoteBase < Ci::Database + self.abstract_class = true + + def generate_code + [*'a'..'z',*'0'..'9',*'A'..'Z'].sample(32).join + end + +end diff --git a/app/models/ci/repo.rb b/app/models/ci/repo.rb new file mode 100644 index 00000000..8396cfa9 --- /dev/null +++ b/app/models/ci/repo.rb @@ -0,0 +1,64 @@ +class Ci::Repo < Ci::RemoteBase + self.primary_key = 'repo_id' + + belongs_to :user, foreign_key: :repo_user_id + has_one :perm, foreign_key: :perm_repo_uid + has_many :builds, foreign_key: :build_repo_id, dependent: :destroy + + def self.find_with_namespace(namespace_path, identifier) + logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} " + + user = Ci::User.find_by_user_login namespace_path + repo = Ci::Repo.where(repo_namespace: namespace_path, repo_name: identifier).first + + [user, repo] + 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) + end + + def self.auto_create!(user, project) + repo = new( + repo_user_id: user.user_id, + repo_namespace: project.owner.login, + repo_name: project.identifier, + repo_slug: "#{project.owner.login}/#{project.identifier}", + repo_scm: "git", + repo_ssh_url: "", + repo_html_url: "", + repo_clone_url: project.repository.url, + repo_active: 1, + repo_private: true, + repo_visibility: 'private', + repo_branch: 'master', + repo_counter: 0, + repo_trusted: false, + repo_protected: false, + repo_synced: 0, + repo_version: 1, + repo_timeout: 60, + repo_config: '.trustie-pipeline.yml', + repo_created: Time.now.to_i, + repo_updated: Time.now.to_i + ) + + repo.repo_signer = repo.generate_code + repo.repo_secret = repo.generate_code + if repo.save! + Ci::Perm.auto_create!(user, repo) + repo.update_column(:repo_uid, repo.id) + repo + end + end + + def deactivate! + update_column(:repo_active, 0) + end +end diff --git a/app/models/ci/stage.rb b/app/models/ci/stage.rb new file mode 100644 index 00000000..2309f05d --- /dev/null +++ b/app/models/ci/stage.rb @@ -0,0 +1,6 @@ +class Ci::Stage < Ci::RemoteBase + self.primary_key = 'stage_id' + + belongs_to :build, foreign_key: :stage_build_id + has_many :steps, foreign_key: "step_stage_id", dependent: :destroy +end diff --git a/app/models/ci/step.rb b/app/models/ci/step.rb new file mode 100644 index 00000000..eed7d6a7 --- /dev/null +++ b/app/models/ci/step.rb @@ -0,0 +1,6 @@ +class Ci::Step < Ci::RemoteBase + self.primary_key = 'step_id' + + belongs_to :stage, foreign_key: :step_stage_id + has_one :log, class_name: 'Ci::Log', foreign_key: :log_id +end diff --git a/app/models/ci/user.rb b/app/models/ci/user.rb new file mode 100644 index 00000000..fd17adce --- /dev/null +++ b/app/models/ci/user.rb @@ -0,0 +1,72 @@ +# == Schema Information +# +# Table name: users +# +# id :integer not null +# login :string(255) default(""), not null +# hashed_password :string(40) default(""), not null +# firstname :string(30) default(""), not null +# lastname :string(255) default(""), not null +# mail :string(60) +# admin :boolean default("0"), not null +# status :integer default("1"), not null +# last_login_on :datetime +# language :string(5) default("") +# auth_source_id :integer +# created_on :datetime +# updated_on :datetime +# type :string(255) +# identity_url :string(255) +# mail_notification :string(255) default(""), not null +# salt :string(64) +# gid :integer +# visits :integer default("0") +# excellent_teacher :integer default("0") +# excellent_student :integer default("0") +# phone :string(255) +# authentication :boolean default("0") +# grade :integer default("0") +# experience :integer default("0") +# nickname :string(255) +# show_realname :boolean default("1") +# professional_certification :boolean default("0") +# ID_number :string(255) +# certification :integer default("0") +# homepage_teacher :boolean default("0") +# homepage_engineer :boolean default("0") +# is_test :integer default("0") +# ecoder_user_id :integer default("0") +# business :boolean default("0") +# profile_completed :boolean default("0") +# laboratory_id :integer +# platform :string(255) default("0") +# gitea_token :string(255) +# gitea_uid :integer +# is_shixun_marker :boolean default("0") +# is_sync_pwd :boolean default("1") +# watchers_count :integer default("0") +# visibility :string(255) default("public") +# repo_admin_change_team_access :boolean default("1") +# is_org :boolean default("0") +# website :string(255) +# devops_step :integer default("0") +# +# Indexes +# +# index_users_on_ecoder_user_id (ecoder_user_id) +# index_users_on_homepage_engineer (homepage_engineer) +# index_users_on_homepage_teacher (homepage_teacher) +# index_users_on_laboratory_id (laboratory_id) +# index_users_on_login (login) +# index_users_on_mail (mail) +# index_users_on_type (type) +# + +class Ci::User < Ci::RemoteBase + self.primary_key = 'user_id' + + has_many :repos, foreign_key: :repo_user_id, dependent: :destroy + has_many :perms, foreign_key: :perm_user_id, dependent: :delete_all + has_one :ci_cloud_account, class_name: 'Ci::CloudAccount', foreign_key: :ci_user_id + +end diff --git a/app/models/compose.rb b/app/models/compose.rb index 0b373394..8d9467dd 100644 --- a/app/models/compose.rb +++ b/app/models/compose.rb @@ -1,3 +1,23 @@ +# == Schema Information +# +# Table name: composes +# +# id :integer not null, primary key +# user_id :integer +# title :string(255) +# description :text(65535) +# show_mode :integer default("0") +# compose_mode :boolean default("0") +# compose_users_count :integer default("0") +# compose_projects_count :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_composes_on_user_id_and_show_mode_and_compose_mode (user_id,show_mode,compose_mode) +# + class Compose < ApplicationRecord #组织 belongs_to :user diff --git a/app/models/compose_project.rb b/app/models/compose_project.rb index 3c2d099e..1468fb05 100644 --- a/app/models/compose_project.rb +++ b/app/models/compose_project.rb @@ -1,3 +1,20 @@ +# == Schema Information +# +# Table name: compose_projects +# +# id :integer not null, primary key +# user_id :integer +# project_id :integer +# compose_id :integer +# position :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_compose_projects_on_user_id_and_project_id_and_compose_id (user_id,project_id,compose_id) +# + class ComposeProject < ApplicationRecord #组织的项目记录表 belongs_to :compose diff --git a/app/models/compose_user.rb b/app/models/compose_user.rb index e3b514b3..a4d33440 100644 --- a/app/models/compose_user.rb +++ b/app/models/compose_user.rb @@ -1,3 +1,19 @@ +# == Schema Information +# +# Table name: compose_users +# +# id :integer not null, primary key +# user_id :integer +# compose_id :integer +# is_manager :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_compose_users_on_user_id_and_compose_id (user_id,compose_id) +# + class ComposeUser < ApplicationRecord belongs_to :compose belongs_to :user diff --git a/app/models/concerns/droneable.rb b/app/models/concerns/droneable.rb new file mode 100644 index 00000000..f91b9f98 --- /dev/null +++ b/app/models/concerns/droneable.rb @@ -0,0 +1,46 @@ +module Droneable + extend ActiveSupport::Concern + + included do + end + + def devops_uninit? + self.devops_step === User::DEVOPS_UNINIT + end + + def devops_unverified? + self.devops_step === User::DEVOPS_UNVERIFIED + end + + def devops_certification? + self.devops_step === User::DEVOPS_CERTIFICATION + end + + def set_drone_step!(step) + self.update_column(:devops_step, step) + end + + def ci_certification? + return false if self.is_a?(AnonymousUser) + devops_certification? && Ci::User.exists?(user_login: self.login) + end + + def unbind_account! + user_projects = self.projects + + user_projects.update_all(open_devops: false, open_devops_count: 0) + set_drone_step!(User::DEVOPS_UNINIT) + + # TODO + # 删除用户项目下的与ci相关的所有webhook + user_projects.select(:id, :identifier, :gitea_webhook_id).each do |project| + if project.gitea_webhook_id + result = Gitea::Hooks::DestroyService.call(self.gitea_token, self.login, project.identifier, project.gitea_webhook_id) + project.update_column(:gitea_webhook_id, nil) if result.status == 204 + end + end + end + + module ClassMethods + end +end diff --git a/app/models/concerns/matchable.rb b/app/models/concerns/matchable.rb index 943fb5ec..aa9fbe81 100644 --- a/app/models/concerns/matchable.rb +++ b/app/models/concerns/matchable.rb @@ -5,6 +5,7 @@ module Matchable scope :with_project_category, ->(category_id) { where(project_category_id: category_id) unless category_id.blank? } scope :with_project_language, ->(language_id) { where(project_language_id: language_id) unless language_id.blank? } scope :with_project_type, ->(project_type) { where(project_type: project_type) if Project.project_types.include?(project_type) } + scope :by_name_or_identifier, ->(search) { where("name like :search or identifier LIKE :search", :search => "#{search.split(" ").join('|')}%") unless search.blank? } end end diff --git a/app/models/concerns/project_ability.rb b/app/models/concerns/project_ability.rb new file mode 100644 index 00000000..682f6fdc --- /dev/null +++ b/app/models/concerns/project_ability.rb @@ -0,0 +1,14 @@ +module ProjectAbility + extend ActiveSupport::Concern + + included do + + end + + def can_read_project?(project) + return true if self.admin? + return false if !project.is_public? && !project.member?(self.id) + true + end + +end diff --git a/app/models/coo_img.rb b/app/models/coo_img.rb index 0766c072..db96ecbd 100644 --- a/app/models/coo_img.rb +++ b/app/models/coo_img.rb @@ -1,5 +1,18 @@ +# == Schema Information +# +# Table name: coo_imgs +# +# id :integer not null, primary key +# src_states :string(255) +# url_states :string(255) +# img_type :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# position :integer +# + class CooImg < ApplicationRecord extend Enumerize enumerize :img_type, in: %i[com_coop edu_coop alliance_coop] -end \ No newline at end of file +end diff --git a/app/models/diff_record.rb b/app/models/diff_record.rb index afbb9dd9..4b40372a 100644 --- a/app/models/diff_record.rb +++ b/app/models/diff_record.rb @@ -1,3 +1,21 @@ +# == Schema Information +# +# Table name: diff_records +# +# id :integer not null, primary key +# user_id :integer +# container_type :string(255) +# container_id :integer +# column_name :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_diff_records_on_container_type_and_container_id (container_type,container_id) +# index_diff_records_on_user_id (user_id) +# + class DiffRecord < ApplicationRecord belongs_to :user belongs_to :container, polymorphic: true @@ -5,4 +23,4 @@ class DiffRecord < ApplicationRecord has_one :diff_record_content, dependent: :destroy delegate :content, to: :diff_record_content -end \ No newline at end of file +end diff --git a/app/models/diff_record_content.rb b/app/models/diff_record_content.rb index ce5e1d35..c479469e 100644 --- a/app/models/diff_record_content.rb +++ b/app/models/diff_record_content.rb @@ -1,3 +1,16 @@ +# == Schema Information +# +# Table name: diff_record_contents +# +# id :integer not null, primary key +# diff_record_id :integer +# content :text(65535) +# +# Indexes +# +# index_diff_record_contents_on_diff_record_id (diff_record_id) +# + class DiffRecordContent < ApplicationRecord belongs_to :diff_record -end \ No newline at end of file +end diff --git a/app/models/edu_setting.rb b/app/models/edu_setting.rb index 835aaec7..6968b008 100644 --- a/app/models/edu_setting.rb +++ b/app/models/edu_setting.rb @@ -1,3 +1,19 @@ +# == Schema Information +# +# Table name: edu_settings +# +# id :integer not null, primary key +# name :string(255) +# value :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# description :string(255) +# +# Indexes +# +# index_edu_settings_on_name (name) UNIQUE +# + class EduSetting < ApplicationRecord after_commit :expire_value_cache diff --git a/app/models/fork_user.rb b/app/models/fork_user.rb index 10ae3232..d0915f15 100644 --- a/app/models/fork_user.rb +++ b/app/models/fork_user.rb @@ -1,4 +1,23 @@ +# == Schema Information +# +# Table name: fork_users +# +# id :integer not null, primary key +# project_id :integer +# fork_project_id :integer +# user_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_fork_users_on_project_id (project_id) +# index_fork_users_on_user_id (user_id) +# + class ForkUser < ApplicationRecord - belongs_to :project + belongs_to :project belongs_to :user + belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id + end diff --git a/app/models/gitea/base.rb b/app/models/gitea/base.rb new file mode 100644 index 00000000..d14249bf --- /dev/null +++ b/app/models/gitea/base.rb @@ -0,0 +1,4 @@ +class Gitea::Base < Gitea::Database + self.abstract_class = true + +end diff --git a/app/models/ignore.rb b/app/models/ignore.rb index bd75ed08..a6dc9a5a 100644 --- a/app/models/ignore.rb +++ b/app/models/ignore.rb @@ -1,3 +1,14 @@ +# == Schema Information +# +# Table name: ignores +# +# id :integer not null, primary key +# name :string(255) +# content :text(65535) +# created_at :datetime not null +# updated_at :datetime not null +# + class Ignore < ApplicationRecord include Projectable end diff --git a/app/models/issue.rb b/app/models/issue.rb index d7dd3bbb..934e1d31 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -1,3 +1,53 @@ +# == Schema Information +# +# Table name: issues +# +# id :integer not null, primary key +# tracker_id :integer not null +# project_id :integer not null +# subject :string(255) default(""), not null +# description :text(4294967295) +# due_date :date +# category_id :integer +# status_id :integer not null +# assigned_to_id :integer +# priority_id :integer not null +# fixed_version_id :integer +# author_id :integer not null +# created_on :datetime +# updated_on :datetime +# start_date :date +# done_ratio :integer default("0"), not null +# estimated_hours :float(24) +# parent_id :integer +# root_id :integer +# lft :integer +# rgt :integer +# is_private :boolean default("0"), not null +# closed_on :datetime +# project_issues_index :integer +# issue_type :string(255) +# token :integer default("0") +# issue_tags_value :string(255) +# is_lock :boolean default("0") +# issue_classify :string(255) +# ref_name :string(255) +# branch_name :string(255) +# +# Indexes +# +# index_issues_on_assigned_to_id (assigned_to_id) +# index_issues_on_author_id (author_id) +# index_issues_on_category_id (category_id) +# index_issues_on_created_on (created_on) +# index_issues_on_fixed_version_id (fixed_version_id) +# index_issues_on_priority_id (priority_id) +# index_issues_on_root_id_and_lft_and_rgt (root_id,lft,rgt) +# index_issues_on_status_id (status_id) +# index_issues_on_tracker_id (tracker_id) +# issues_project_id (project_id) +# + class Issue < ApplicationRecord #issue_type 1为普通,2为悬赏 belongs_to :project, :counter_cache => true diff --git a/app/models/issue_depend.rb b/app/models/issue_depend.rb index 14686e86..8b64dc1f 100644 --- a/app/models/issue_depend.rb +++ b/app/models/issue_depend.rb @@ -1,3 +1,19 @@ +# == Schema Information +# +# Table name: issue_depends +# +# id :integer not null, primary key +# user_id :integer +# issue_id :integer +# depend_issue_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_issue_depends_on_user_id_and_issue_id_and_depend_issue_id (user_id,issue_id,depend_issue_id) +# + class IssueDepend < ApplicationRecord belongs_to :issue end diff --git a/app/models/issue_priority.rb b/app/models/issue_priority.rb index 6b815f42..27865a70 100644 --- a/app/models/issue_priority.rb +++ b/app/models/issue_priority.rb @@ -1,3 +1,18 @@ +# == Schema Information +# +# Table name: issue_priorities +# +# id :integer not null, primary key +# name :string(255) +# position :integer +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_issue_priorities_on_name (name) +# + class IssuePriority < ApplicationRecord has_many :issues -end \ No newline at end of file +end diff --git a/app/models/issue_status.rb b/app/models/issue_status.rb index 82bc62ab..a7ec34f8 100644 --- a/app/models/issue_status.rb +++ b/app/models/issue_status.rb @@ -1,4 +1,22 @@ +# == Schema Information +# +# Table name: issue_statuses +# +# id :integer not null, primary key +# name :string(30) default(""), not null +# is_closed :boolean default("0"), not null +# is_default :boolean default("0"), not null +# position :integer default("1") +# default_done_ratio :integer +# +# Indexes +# +# index_issue_statuses_on_is_closed (is_closed) +# index_issue_statuses_on_is_default (is_default) +# index_issue_statuses_on_position (position) +# + class IssueStatus < ApplicationRecord has_many :issues belongs_to :project, optional: true -end \ No newline at end of file +end diff --git a/app/models/issue_tag.rb b/app/models/issue_tag.rb index 7b61f401..bf236865 100644 --- a/app/models/issue_tag.rb +++ b/app/models/issue_tag.rb @@ -1,3 +1,24 @@ +# == Schema Information +# +# Table name: issue_tags +# +# id :integer not null, primary key +# name :string(255) +# description :string(255) +# color :string(255) +# user_id :integer +# project_id :integer +# issues_count :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# gid :integer +# gitea_url :string(255) +# +# Indexes +# +# index_issue_tags_on_user_id_and_name_and_project_id (user_id,name,project_id) +# + class IssueTag < ApplicationRecord has_many :issue_tags_relates, dependent: :destroy diff --git a/app/models/issue_tags_relate.rb b/app/models/issue_tags_relate.rb index bab48d40..df9fd81a 100644 --- a/app/models/issue_tags_relate.rb +++ b/app/models/issue_tags_relate.rb @@ -1,3 +1,18 @@ +# == Schema Information +# +# Table name: issue_tags_relates +# +# id :integer not null, primary key +# issue_id :integer +# issue_tag_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_issue_tags_relates_on_issue_id_and_issue_tag_id (issue_id,issue_tag_id) +# + class IssueTagsRelate < ApplicationRecord belongs_to :issue belongs_to :issue_tag, counter_cache: :issues_count diff --git a/app/models/issue_time.rb b/app/models/issue_time.rb index 10d7af7b..24425d1e 100644 --- a/app/models/issue_time.rb +++ b/app/models/issue_time.rb @@ -1,3 +1,21 @@ +# == Schema Information +# +# Table name: issue_times +# +# id :integer not null, primary key +# issue_id :integer +# user_id :integer +# start_time :datetime +# end_time :datetime +# cost_time :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_issue_times_on_issue_id_and_user_id (issue_id,user_id) +# + class IssueTime < ApplicationRecord belongs_to :issue belongs_to :user diff --git a/app/models/journal.rb b/app/models/journal.rb index f730878d..a1834ae2 100644 --- a/app/models/journal.rb +++ b/app/models/journal.rb @@ -1,3 +1,26 @@ +# == Schema Information +# +# Table name: journals +# +# id :integer not null, primary key +# journalized_id :integer default("0"), not null +# journalized_type :string(30) default(""), not null +# user_id :integer default("0"), not null +# notes :text(65535) +# created_on :datetime not null +# private_notes :boolean default("0"), not null +# parent_id :integer +# comments_count :integer default("0") +# reply_id :integer +# +# Indexes +# +# index_journals_on_created_on (created_on) +# index_journals_on_journalized_id (journalized_id) +# index_journals_on_user_id (user_id) +# journals_journalized_id (journalized_id,journalized_type) +# + class Journal < ApplicationRecord belongs_to :user belongs_to :issue, foreign_key: :journalized_id, :touch => true @@ -150,4 +173,4 @@ class Journal < ApplicationRecord end -end \ No newline at end of file +end diff --git a/app/models/journal_detail.rb b/app/models/journal_detail.rb index c97bdf37..f5f21260 100644 --- a/app/models/journal_detail.rb +++ b/app/models/journal_detail.rb @@ -1,3 +1,19 @@ +# == Schema Information +# +# Table name: journal_details +# +# id :integer not null, primary key +# journal_id :integer default("0"), not null +# property :string(30) default(""), not null +# prop_key :string(30) default(""), not null +# old_value :text(65535) +# value :text(65535) +# +# Indexes +# +# journal_details_journal_id (journal_id) +# + class JournalDetail < ApplicationRecord belongs_to :journal -end \ No newline at end of file +end diff --git a/app/models/journals_for_message.rb b/app/models/journals_for_message.rb index 3d0189c9..090edcb8 100644 --- a/app/models/journals_for_message.rb +++ b/app/models/journals_for_message.rb @@ -1,3 +1,32 @@ +# == Schema Information +# +# Table name: journals_for_messages +# +# id :integer not null, primary key +# jour_id :integer +# jour_type :string(255) +# user_id :integer +# notes :text(65535) +# status :integer +# reply_id :integer +# created_on :datetime not null +# updated_on :datetime not null +# m_parent_id :string(255) +# is_readed :boolean +# m_reply_count :integer +# m_reply_id :integer +# is_comprehensive_evaluation :integer +# private :integer default("0") +# root_id :integer +# hidden :boolean default("0") +# praises_count :integer default("0") +# +# Indexes +# +# index_journals_for_messages_on_jour_id (jour_id) +# index_journals_for_messages_on_root_id (root_id) +# + class JournalsForMessage < ApplicationRecord belongs_to :jour, :polymorphic => true belongs_to :user diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index f53a2afe..699800c9 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -1,3 +1,22 @@ +# == Schema Information +# +# Table name: laboratories +# +# id :integer not null, primary key +# school_id :integer +# identifier :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# sync_course :boolean default("0") +# sync_subject :boolean default("0") +# sync_shixun :boolean default("0") +# +# Indexes +# +# index_laboratories_on_identifier (identifier) UNIQUE +# index_laboratories_on_school_id (school_id) +# + class Laboratory < ApplicationRecord belongs_to :school, optional: true diff --git a/app/models/laboratory_setting.rb b/app/models/laboratory_setting.rb index fbf44e4c..61c677de 100644 --- a/app/models/laboratory_setting.rb +++ b/app/models/laboratory_setting.rb @@ -1,3 +1,16 @@ +# == Schema Information +# +# Table name: laboratory_settings +# +# id :integer not null, primary key +# laboratory_id :integer +# config :text(65535) +# +# Indexes +# +# index_laboratory_settings_on_laboratory_id (laboratory_id) +# + class LaboratorySetting < ApplicationRecord belongs_to :laboratory @@ -63,12 +76,13 @@ class LaboratorySetting < ApplicationRecord navbar: [ { 'name' => '首页', 'link' => '/projects', 'hidden' => false }, { 'name' => '课程', 'link' => '/courses', 'hidden' => false }, - { 'name' => '项目', 'link' => '/projects', 'hidden' => false }, + { 'name' => '项目', 'link' => '', 'hidden' => true }, { 'name' => '数据', 'link' => '/datas', 'hidden' => false }, { 'name' => '竞赛', 'link' => '/competitions', 'hidden' => false }, { 'name' => '问吧', 'link' => '/forums', 'hidden' => false }, + { 'name' => '开源社区', 'link' => '/projects', 'hidden' => false }, ], footer: nil } end -end \ No newline at end of file +end diff --git a/app/models/laboratory_user.rb b/app/models/laboratory_user.rb index be6c0c4d..8658e410 100644 --- a/app/models/laboratory_user.rb +++ b/app/models/laboratory_user.rb @@ -1,4 +1,18 @@ +# == Schema Information +# +# Table name: laboratory_users +# +# id :integer not null, primary key +# laboratory_id :integer +# user_id :integer +# +# Indexes +# +# index_laboratory_users_on_laboratory_id (laboratory_id) +# index_laboratory_users_on_user_id (user_id) +# + class LaboratoryUser < ApplicationRecord belongs_to :laboratory belongs_to :user -end \ No newline at end of file +end diff --git a/app/models/license.rb b/app/models/license.rb index 952c4a13..0a14fb85 100644 --- a/app/models/license.rb +++ b/app/models/license.rb @@ -1,3 +1,14 @@ +# == Schema Information +# +# Table name: licenses +# +# id :integer not null, primary key +# name :string(255) +# content :text(65535) +# created_at :datetime not null +# updated_at :datetime not null +# + class License < ApplicationRecord include Projectable end diff --git a/app/models/member.rb b/app/models/member.rb index 054a072b..e72ae7c6 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -1,3 +1,25 @@ +# == Schema Information +# +# Table name: members +# +# id :integer not null, primary key +# user_id :integer default("0"), not null +# project_id :integer default("0") +# created_on :datetime +# mail_notification :boolean default("0"), not null +# course_id :integer default("-1") +# course_group_id :integer default("0") +# is_collect :integer default("1") +# graduation_group_id :integer default("0") +# +# Indexes +# +# index_members_on_course_id (course_id) +# index_members_on_project_id (project_id) +# index_members_on_user_id (user_id) +# index_members_on_user_id_and_project_id (user_id,project_id,course_id) UNIQUE +# + class Member < ApplicationRecord belongs_to :user # belongs_to :course, optional: true diff --git a/app/models/member_role.rb b/app/models/member_role.rb index 6e51e701..a2011067 100644 --- a/app/models/member_role.rb +++ b/app/models/member_role.rb @@ -1,3 +1,19 @@ +# == Schema Information +# +# Table name: member_roles +# +# id :integer not null, primary key +# member_id :integer not null +# role_id :integer not null +# inherited_from :integer +# is_current :integer default("1") +# +# Indexes +# +# index_member_roles_on_member_id (member_id) +# index_member_roles_on_role_id (role_id) +# + class MemberRole < ApplicationRecord belongs_to :role belongs_to :member diff --git a/app/models/mirror.rb b/app/models/mirror.rb index f5737b0f..67ef7377 100644 --- a/app/models/mirror.rb +++ b/app/models/mirror.rb @@ -1,11 +1,26 @@ +# == Schema Information +# +# Table name: mirrors +# +# id :integer not null, primary key +# repo_id :integer +# status :integer default("0"), not null +# interval :integer +# next_update_time :datetime +# created_at :datetime not null +# updated_at :datetime not null +# sync_num :integer default("1") +# + class Mirror < ApplicationRecord # 0 - succeeded, 1 - waiting, 2 - failed # 0: 同步镜像成功;1: 正在同步镜像;2: 同步失败; 默认值为0 enum status: { succeeded: 0, waiting: 1, failed: 2 } - belongs_to :repository, foreign_key: :repo_id + after_update :websocket_boardcast, if: :saved_change_to_status? + belongs_to :repository, foreign_key: :repo_id def set_status!(status=Mirror.statuses[:succeeded]) update_column(:status, status) @@ -14,4 +29,9 @@ class Mirror < ApplicationRecord def numerical_for_status self.class.name.constantize.statuses["#{self.status}"] end + + private + def websocket_boardcast + BroadcastMirrorRepoMsgJob.perform_later(self.repository.id) + end end diff --git a/app/models/oauth.rb b/app/models/oauth.rb new file mode 100644 index 00000000..90d8b61b --- /dev/null +++ b/app/models/oauth.rb @@ -0,0 +1,29 @@ +# == Schema Information +# +# Table name: oauths +# +# id :integer not null, primary key +# client_id :string(255) +# client_secret :string(255) +# code :string(255) +# redirect_uri :string(255) +# scope :string(255) +# access_token :string(255) +# refresh_token :string(255) +# token_created_at :integer +# token_expires_in :integer +# created_at :datetime not null +# updated_at :datetime not null +# user_id :integer default("0") +# gitea_oauth_id :integer +# project_id :integer +# +# Indexes +# +# index_oauths_on_user_id (user_id) +# + +# for oauth2 application +class Oauth < ApplicationRecord + belongs_to :user +end diff --git a/app/models/onclick_time.rb b/app/models/onclick_time.rb index 588da23f..ac064327 100644 --- a/app/models/onclick_time.rb +++ b/app/models/onclick_time.rb @@ -1,3 +1,18 @@ +# == Schema Information +# +# Table name: onclick_times +# +# id :integer not null, primary key +# user_id :integer +# onclick_time :datetime +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_onclick_times_on_user_id (user_id) +# + class OnclickTime < ApplicationRecord belongs_to :user diff --git a/app/models/open_user.rb b/app/models/open_user.rb index 45c4ee6b..b7d90e71 100644 --- a/app/models/open_user.rb +++ b/app/models/open_user.rb @@ -1,3 +1,21 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + class OpenUser < ApplicationRecord belongs_to :user @@ -8,4 +26,4 @@ class OpenUser < ApplicationRecord def can_bind_cache_key "open_user:#{type}:#{uid}:can_bind" end -end \ No newline at end of file +end diff --git a/app/models/open_users/cas.rb b/app/models/open_users/cas.rb index 301a197a..df7fb515 100644 --- a/app/models/open_users/cas.rb +++ b/app/models/open_users/cas.rb @@ -1,3 +1,21 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + class OpenUsers::Cas < OpenUser def nickname extra&.[]('nickname') @@ -6,4 +24,4 @@ class OpenUsers::Cas < OpenUser def en_type 'cas' end -end \ No newline at end of file +end diff --git a/app/models/open_users/educoder.rb b/app/models/open_users/educoder.rb new file mode 100644 index 00000000..310cf951 --- /dev/null +++ b/app/models/open_users/educoder.rb @@ -0,0 +1,27 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + +class OpenUsers::Educoder < OpenUser + def nickname + extra&.[]('nickname') + end + + def en_type + 'educoder' + end +end diff --git a/app/models/open_users/qq.rb b/app/models/open_users/qq.rb index 9e782712..ef1a4b47 100644 --- a/app/models/open_users/qq.rb +++ b/app/models/open_users/qq.rb @@ -1,3 +1,21 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + class OpenUsers::QQ < OpenUser def nickname extra&.[]('nickname') @@ -6,4 +24,4 @@ class OpenUsers::QQ < OpenUser def en_type 'qq' end -end \ No newline at end of file +end diff --git a/app/models/open_users/wechat.rb b/app/models/open_users/wechat.rb index 9e7e032b..5cb22126 100644 --- a/app/models/open_users/wechat.rb +++ b/app/models/open_users/wechat.rb @@ -1,3 +1,21 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + class OpenUsers::Wechat < OpenUser def nickname extra&.[]('nickname') @@ -6,4 +24,4 @@ class OpenUsers::Wechat < OpenUser def en_type 'wechat' end -end \ No newline at end of file +end diff --git a/app/models/praise_tread.rb b/app/models/praise_tread.rb index cdfdbea2..123bbbdc 100644 --- a/app/models/praise_tread.rb +++ b/app/models/praise_tread.rb @@ -1,3 +1,16 @@ +# == Schema Information +# +# Table name: praise_treads +# +# id :integer not null, primary key +# user_id :integer not null +# praise_tread_object_id :integer +# praise_tread_object_type :string(255) +# praise_or_tread :integer +# created_at :datetime not null +# updated_at :datetime not null +# + class PraiseTread < ApplicationRecord belongs_to :user belongs_to :praise_tread_object, polymorphic: true, counter_cache: :praises_count diff --git a/app/models/praise_tread_cache.rb b/app/models/praise_tread_cache.rb index 5544d185..b6fe0887 100644 --- a/app/models/praise_tread_cache.rb +++ b/app/models/praise_tread_cache.rb @@ -1,2 +1,15 @@ +# == Schema Information +# +# Table name: praise_tread_caches +# +# id :integer not null, primary key +# object_id :integer not null +# object_type :string(255) +# praise_num :integer +# tread_num :integer +# created_at :datetime not null +# updated_at :datetime not null +# + class PraiseTreadCache < ApplicationRecord end diff --git a/app/models/private_message.rb b/app/models/private_message.rb index 640e48db..bb6d1679 100644 --- a/app/models/private_message.rb +++ b/app/models/private_message.rb @@ -1,3 +1,23 @@ +# == Schema Information +# +# Table name: private_messages +# +# id :integer not null, primary key +# user_id :integer +# target_id :integer +# sender_id :integer +# receiver_id :integer +# content :text(65535) +# send_time :datetime +# status :integer +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_private_messages_on_user_id (user_id) +# + class PrivateMessage < ApplicationRecord belongs_to :user belongs_to :target, class_name: "User" diff --git a/app/models/project.rb b/app/models/project.rb index f4fb1122..887a6952 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,3 +1,73 @@ +# == Schema Information +# +# Table name: projects +# +# id :integer not null, primary key +# name :string(255) default(""), not null +# description :text(4294967295) +# homepage :string(255) default("") +# is_public :boolean default("1"), not null +# parent_id :integer +# created_on :datetime +# updated_on :datetime +# identifier :string(255) +# status :integer default("1"), not null +# lft :integer +# rgt :integer +# inherit_members :boolean default("0"), not null +# project_type :integer default("0") +# hidden_repo :boolean default("0"), not null +# attachmenttype :integer default("1") +# user_id :integer +# dts_test :integer default("0") +# enterprise_name :string(255) +# organization_id :integer +# project_new_type :integer +# gpid :integer +# forked_from_project_id :integer +# forked_count :integer default("0") +# publish_resource :integer default("0") +# visits :integer default("0") +# hot :integer default("0") +# invite_code :string(255) +# qrcode :string(255) +# qrcode_expiretime :integer default("0") +# script :text(65535) +# training_status :integer default("0") +# rep_identifier :string(255) +# project_category_id :integer +# project_language_id :integer +# license_id :integer +# ignore_id :integer +# praises_count :integer default("0") +# watchers_count :integer default("0") +# issues_count :integer default("0") +# pull_requests_count :integer default("0") +# language :string(255) +# versions_count :integer default("0") +# issue_tags_count :integer default("0") +# closed_issues_count :integer default("0") +# open_devops :boolean default("0") +# gitea_webhook_id :integer +# open_devops_count :integer default("0") +# recommend :boolean default("0") +# platform :integer default("0") +# +# Indexes +# +# index_projects_on_forked_from_project_id (forked_from_project_id) +# index_projects_on_identifier (identifier) +# index_projects_on_is_public (is_public) +# index_projects_on_lft (lft) +# index_projects_on_name (name) +# index_projects_on_platform (platform) +# index_projects_on_project_type (project_type) +# index_projects_on_recommend (recommend) +# index_projects_on_rgt (rgt) +# index_projects_on_status (status) +# index_projects_on_updated_on (updated_on) +# + class Project < ApplicationRecord include Matchable include Publicable @@ -10,15 +80,19 @@ class Project < ApplicationRecord # enum project_type: { sync_mirror: 2, mirror: 1, common: 0 } + # forge: trustie平台项目, educoder: educoder平台项目, 默认为forge平台 + enum platform: { forge: 0, educoder: 1 } + belongs_to :ignore, optional: true belongs_to :license, optional: true - belongs_to :owner, class_name: 'User', foreign_key: :user_id + belongs_to :owner, class_name: 'User', foreign_key: :user_id, optional: true belongs_to :project_category, optional: true , :counter_cache => true belongs_to :project_language, optional: true , :counter_cache => true has_many :project_trends, dependent: :destroy has_many :watchers, as: :watchable, dependent: :destroy has_many :fork_users, dependent: :destroy - # has_many :commits, dependent: :destroy + has_many :forked_users, class_name: 'ForkUser', foreign_key: :fork_project_id, dependent: :destroy + has_one :project_educoder, dependent: :destroy has_one :project_score, dependent: :destroy has_one :repository, dependent: :destroy @@ -31,10 +105,13 @@ class Project < ApplicationRecord has_many :versions, -> { order("versions.created_on DESC, versions.name DESC") }, dependent: :destroy has_many :praise_treads, as: :praise_tread_object, dependent: :destroy has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" + has_one :project_detail, dependent: :destroy after_save :check_project_members scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)} scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)} + scope :recommend, -> { visible.project_statics_select.where(recommend: true) } + def self.search_project(search) @@ -160,7 +237,7 @@ class Project < ApplicationRecord member&.roles&.last&.name || permission end - def fork_project + def fork_project Project.find_by(id: self.forked_from_project_id) end @@ -168,4 +245,38 @@ class Project < ApplicationRecord joins(:members).where(members: { user_id: member_user_id}) end + def self.find_with_namespace(namespace_path, identifier) + logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} " + + user = User.find_by_login namespace_path + project = user&.projects&.find_by(identifier: identifier) || Project.find_by(identifier: "#{namespace_path}/#{identifier}") + return nil if project.blank? + + [project, user] + end + + def ci_reactivate? + open_devops_count > 0 + end + + def ci_reactivate!(ci_repo) + ci_repo.update_column(:repo_active, 1) + update_column(:open_devops, true) + increment!(:open_devops_count) + end + + def self.sync_educoder_shixun(url, private_token, page, per_page) + SyncEducoderShixunJob.perform_later(url, private_token, page, per_page) + end + + def self.update_common_projects_count! + ps = ProjectStatistic.first + ps.increment!(:common_projects_count) unless ps.blank? + end + + def self.update_mirror_projects_count! + ps = ProjectStatistic.first + ps.increment!(:mirror_projects_count) unless ps.blank? + end + end diff --git a/app/models/project_category.rb b/app/models/project_category.rb index ff9c0a84..3a981981 100644 --- a/app/models/project_category.rb +++ b/app/models/project_category.rb @@ -1,3 +1,20 @@ +# == Schema Information +# +# Table name: project_categories +# +# id :integer not null, primary key +# name :string(255) +# position :integer +# projects_count :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# ancestry :string(255) +# +# Indexes +# +# index_project_categories_on_ancestry (ancestry) +# + class ProjectCategory < ApplicationRecord include Projectable has_ancestry diff --git a/app/models/project_detail.rb b/app/models/project_detail.rb new file mode 100644 index 00000000..b7ae215c --- /dev/null +++ b/app/models/project_detail.rb @@ -0,0 +1,19 @@ +# == Schema Information +# +# Table name: project_details +# +# id :integer not null, primary key +# project_id :integer +# content :text(4294967295) +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_project_details_on_project_id (project_id) +# + +class ProjectDetail < ApplicationRecord + belongs_to :project, optional: true + has_many :attachments, as: :container, dependent: :destroy +end diff --git a/app/models/project_educoder.rb b/app/models/project_educoder.rb new file mode 100644 index 00000000..a8146af4 --- /dev/null +++ b/app/models/project_educoder.rb @@ -0,0 +1,23 @@ +# == Schema Information +# +# Table name: project_educoders +# +# id :integer not null, primary key +# owner :string(255) +# repo_name :string(255) +# image_url :string(255) +# project_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# commit_count :integer default("0") +# forked_count :integer default("0") +# +# Indexes +# +# index_project_educoders_on_project_id (project_id) +# index_project_educoders_on_repo_name (repo_name) +# + +class ProjectEducoder < ApplicationRecord + belongs_to :project, optional: true +end diff --git a/app/models/project_language.rb b/app/models/project_language.rb index 386c274e..ced6c5f9 100644 --- a/app/models/project_language.rb +++ b/app/models/project_language.rb @@ -1,3 +1,15 @@ +# == Schema Information +# +# Table name: project_languages +# +# id :integer not null, primary key +# name :string(255) +# position :integer +# projects_count :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# + class ProjectLanguage < ApplicationRecord include Projectable end diff --git a/app/models/project_package.rb b/app/models/project_package.rb index a8e13491..e6584264 100644 --- a/app/models/project_package.rb +++ b/app/models/project_package.rb @@ -1,3 +1,31 @@ +# == Schema Information +# +# Table name: project_packages +# +# id :integer not null, primary key +# creator_id :integer +# status :string(255) +# title :string(255) +# content :text(65535) +# contact_name :string(255) +# contact_phone :string(255) +# min_price :decimal(10, ) +# max_price :decimal(10, ) +# visit_count :integer default("0") +# bidding_users_count :integer default("0") +# deadline_at :datetime +# published_at :datetime +# bidding_finished_at :datetime +# created_at :datetime not null +# updated_at :datetime not null +# project_package_category_id :integer +# +# Indexes +# +# index_project_packages_on_creator_id (creator_id) +# index_project_packages_on_published_at (published_at) +# + class ProjectPackage < ApplicationRecord include AASM diff --git a/app/models/project_package_apply.rb b/app/models/project_package_apply.rb index 0dd69c0c..9f0c2b01 100644 --- a/app/models/project_package_apply.rb +++ b/app/models/project_package_apply.rb @@ -1,3 +1,20 @@ +# == Schema Information +# +# Table name: project_package_applies +# +# id :integer not null, primary key +# project_package_id :integer +# status :string(255) +# reason :string(255) +# refused_at :datetime +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_project_package_applies_on_project_package_id (project_package_id) +# + class ProjectPackageApply < ApplicationRecord include AASM @@ -16,4 +33,4 @@ class ProjectPackageApply < ApplicationRecord transitions from: :pending, to: :agreed end end -end \ No newline at end of file +end diff --git a/app/models/project_package_category.rb b/app/models/project_package_category.rb index 403fdf4c..9db319dd 100644 --- a/app/models/project_package_category.rb +++ b/app/models/project_package_category.rb @@ -1,3 +1,12 @@ +# == Schema Information +# +# Table name: project_package_categories +# +# id :integer not null, primary key +# name :string(255) +# position :integer +# + class ProjectPackageCategory < ApplicationRecord default_scope { order(position: :asc) } @@ -20,4 +29,4 @@ class ProjectPackageCategory < ApplicationRecord def reset_cache_data Rails.cache.delete(self.class.data_cache_key) end -end \ No newline at end of file +end diff --git a/app/models/project_score.rb b/app/models/project_score.rb index 51ed29a6..24124265 100644 --- a/app/models/project_score.rb +++ b/app/models/project_score.rb @@ -1,3 +1,24 @@ +# == Schema Information +# +# Table name: project_scores +# +# id :integer not null, primary key +# project_id :string(255) +# score :integer +# created_at :datetime not null +# updated_at :datetime not null +# issue_num :integer default("0") +# issue_journal_num :integer default("0") +# news_num :integer default("0") +# documents_num :integer default("0") +# changeset_num :integer default("0") +# board_message_num :integer default("0") +# board_num :integer default("0") +# attach_num :integer default("0") +# commit_time :datetime +# pull_request_num :integer default("0") +# + class ProjectScore < ApplicationRecord belongs_to :project diff --git a/app/models/project_statistic.rb b/app/models/project_statistic.rb new file mode 100644 index 00000000..10eb14a4 --- /dev/null +++ b/app/models/project_statistic.rb @@ -0,0 +1,15 @@ +# == Schema Information +# +# Table name: project_statistics +# +# id :integer not null, primary key +# common_projects_count :integer default("0") +# mirror_projects_count :integer default("0") +# sync_mirror_projects_count :integer default("0") +# commits_total_count :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# + +class ProjectStatistic < ApplicationRecord +end diff --git a/app/models/project_trend.rb b/app/models/project_trend.rb index 28fd0ffa..5858768b 100644 --- a/app/models/project_trend.rb +++ b/app/models/project_trend.rb @@ -1,3 +1,22 @@ +# == Schema Information +# +# Table name: project_trends +# +# id :integer not null, primary key +# user_id :integer +# project_id :integer +# trend_type :string(255) +# trend_id :integer +# action_type :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_project_trends_on_trend_type_and_trend_id (trend_type,trend_id) +# index_project_trends_on_user_id_and_project_id (user_id,project_id) +# + class ProjectTrend < ApplicationRecord belongs_to :project belongs_to :trend, polymorphic: true, optional: true diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb index d752bb85..8a5e1927 100644 --- a/app/models/pull_request.rb +++ b/app/models/pull_request.rb @@ -1,3 +1,28 @@ +# == Schema Information +# +# Table name: pull_requests +# +# id :integer not null, primary key +# pull_request_id :integer +# gpid :integer +# user_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# status :integer default("0") +# project_id :integer +# title :string(255) +# milestone :integer +# body :text(65535) +# head :string(255) +# base :string(255) +# issue_id :integer +# fork_project_id :integer +# is_original :boolean default("0") +# comments_count :integer default("0") +# commits_count :integer default("0") +# files_count :integer default("0") +# + class PullRequest < ApplicationRecord #status 0 默认未合并, 1表示合并, 2表示请求拒绝 belongs_to :issue @@ -12,4 +37,22 @@ class PullRequest < ApplicationRecord def fork_project Project.find_by(id: self.fork_project_id) 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| + puts pr.id + next if pr.gpid.blank? + project = pr.project + + next if project.blank? + user = project.owner + next if pr.gpid === 6 || pr.gpid === 7 + files_result = Gitea::PullRequest::FilesService.call(user.login, project.identifier, pr.gpid) + pr.update_column(:files_count, files_result['NumFiles']) unless files_result.blank? + + commits_result = Gitea::PullRequest::CommitsService.call(user.login, project.identifier, pr.gpid) + pr.update_column(:commits_count, commits_result.size) unless commits_result.blank? + end + end end diff --git a/app/models/pull_request_assign.rb b/app/models/pull_request_assign.rb index 0c47cc88..c8e6489b 100644 --- a/app/models/pull_request_assign.rb +++ b/app/models/pull_request_assign.rb @@ -1,3 +1,19 @@ +# == Schema Information +# +# Table name: pull_request_assigns +# +# id :integer not null, primary key +# pull_request_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# user_login :string(255) +# +# Indexes +# +# index_pull_request_assigns_on_user_id_and_pull_request_id (pull_request_id) +# index_pull_request_assigns_on_user_login (user_login) +# + class PullRequestAssign < ApplicationRecord belongs_to :user belongs_to :pull_request diff --git a/app/models/pull_request_tag.rb b/app/models/pull_request_tag.rb index 58953062..7f2b6d1e 100644 --- a/app/models/pull_request_tag.rb +++ b/app/models/pull_request_tag.rb @@ -1,3 +1,18 @@ +# == Schema Information +# +# Table name: pull_request_tags +# +# id :integer not null, primary key +# issue_tag_id :integer +# pull_request_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_pull_request_tags_on_issue_tag_id_and_pull_request_id (issue_tag_id,pull_request_id) +# + class PullRequestTag < ApplicationRecord belongs_to :issue_tag belongs_to :pull_request diff --git a/app/models/repository.rb b/app/models/repository.rb index 6d20afce..65b4316e 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1,8 +1,41 @@ +# == Schema Information +# +# Table name: repositories +# +# id :integer not null, primary key +# project_id :integer default("0"), not null +# url :string(255) default(""), not null +# login :string(60) default("") +# password :string(255) default("") +# root_url :string(255) default("") +# type :string(255) +# path_encoding :string(64) +# log_encoding :string(64) +# extra_info :text(65535) +# identifier :string(255) +# is_default :boolean default("0") +# hidden :boolean default("0") +# shixun_id :integer +# myshixun_id :integer +# user_id :integer +# mirror_url :string(255) +# version_releases_count :integer default("0") +# fork_url :string(255) +# is_mirror :boolean default("0") +# +# Indexes +# +# index_repositories_on_identifier (identifier) +# index_repositories_on_project_id (project_id) +# index_repositories_on_user_id (user_id) +# + class Repository < ApplicationRecord self.inheritance_column = nil # FIX The single-table inheritance mechanism failed belongs_to :project, :touch => true - belongs_to :user + belongs_to :user, optional: true has_one :mirror, foreign_key: :repo_id + has_one :ci_cloud_account, class_name: 'Ci::CloudAccount', foreign_key: :repo_id has_many :version_releases, dependent: :destroy validates :identifier, presence: true @@ -33,4 +66,12 @@ class Repository < ApplicationRecord repo_mirror.set_status!(Mirror.statuses[:waiting]) repo_mirror.increment!(:sync_num) end + + def generate_hex(column) + loop do + hex = SecureRandom.hex + break hex unless self.class.where(column => hex).any? + end + end + end diff --git a/app/models/role.rb b/app/models/role.rb index e60606ff..0767adec 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -1,3 +1,16 @@ +# == Schema Information +# +# Table name: roles +# +# id :integer not null, primary key +# name :string(30) default(""), not null +# position :integer default("1") +# assignable :boolean default("1") +# builtin :integer default("0"), not null +# permissions :text(65535) +# issues_visibility :string(30) default("default"), not null +# + class Role < ApplicationRecord has_many :member_roles, dependent: :destroy -end \ No newline at end of file +end diff --git a/app/models/sync_log.rb b/app/models/sync_log.rb index f24a0a92..19b8fd8c 100644 --- a/app/models/sync_log.rb +++ b/app/models/sync_log.rb @@ -5,7 +5,12 @@ class SyncLog end def self.sync_project_log(message=nil) - @my_log ||= Logger.new("#{Rails.root}/log/sync_error_project.log") + @my_log ||= Logger.new("#{Rails.root}/log/sync_project_log.log") @my_log.debug(message) unless message.nil? end + + def self.empty_repo_project_log(message=nil) + empt_log ||= Logger.new("#{Rails.root}/log/empty_repo_project_log.log") + empt_log.debug(message) unless message.nil? + end end \ No newline at end of file diff --git a/app/models/system_update_notice.rb b/app/models/system_update_notice.rb index 44589a40..de4bebfb 100644 --- a/app/models/system_update_notice.rb +++ b/app/models/system_update_notice.rb @@ -1,2 +1,16 @@ +# == Schema Information +# +# Table name: system_update_notices +# +# id :integer not null, primary key +# subject :string(255) +# notes :text(65535) +# start_time :datetime +# end_time :datetime +# created_at :datetime not null +# updated_at :datetime not null +# notice_type :integer +# + class SystemUpdateNotice < ApplicationRecord end diff --git a/app/models/tiding.rb b/app/models/tiding.rb index aa570f5c..01daeb96 100644 --- a/app/models/tiding.rb +++ b/app/models/tiding.rb @@ -1,3 +1,30 @@ +# == Schema Information +# +# Table name: tidings +# +# id :integer not null, primary key +# user_id :integer +# trigger_user_id :integer +# container_id :integer +# container_type :string(255) +# parent_container_id :integer +# parent_container_type :string(255) +# belong_container_id :integer +# belong_container_type :string(255) +# status :integer default("0") +# viewed :boolean +# created_at :datetime not null +# updated_at :datetime not null +# tiding_type :string(255) +# extra :string(255) +# is_delete :boolean default("0") +# +# Indexes +# +# index_tidings_on_container_id (container_id) +# index_tidings_on_user_id (user_id) +# + class Tiding < ApplicationRecord belongs_to :user belongs_to :trigger_user, class_name: 'User', optional: true @@ -29,4 +56,4 @@ class Tiding < ApplicationRecord (container_type == 'StudentWorksScore' && extra.to_i == 3) || (container_type == 'StudentWorksScoresAppeal' && parent_container_type == 'StudentWork' && tiding_type == 'System') end -end \ No newline at end of file +end diff --git a/app/models/token.rb b/app/models/token.rb index cd61090b..c71a860a 100644 --- a/app/models/token.rb +++ b/app/models/token.rb @@ -1,3 +1,19 @@ +# == Schema Information +# +# Table name: tokens +# +# id :integer not null, primary key +# user_id :integer default("0"), not null +# action :string(30) default(""), not null +# value :string(40) default(""), not null +# created_on :datetime not null +# +# Indexes +# +# index_tokens_on_user_id (user_id) +# tokens_value (value) UNIQUE +# + # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -27,8 +43,10 @@ class Token < ActiveRecord::Base def self.get_or_create_permanent_login_token(user, type) token = Token.get_token_from_user(user, type) + Rails.logger.info "###### Token.get_token_from_user result: #{token&.value}" unless token token = Token.create(:user => user, :action => type) + Rails.logger.info "###### Token.get_token_from_user is nul and agine create token: #{token&.value}" else token.update_attribute(:created_on, Time.now) end @@ -37,8 +55,10 @@ class Token < ActiveRecord::Base def self.get_token_from_user(user, action) token = Token.where(:action => action, :user_id => user).first + Rails.logger.info "###### self.get_token_from_user query result: #{token&.value}" unless token token = Token.create!(user_id: user.id, action: action) + Rails.logger.info "###### self.get_token_from_user query is nil and create result: #{token&.value}" end token end diff --git a/app/models/tracker.rb b/app/models/tracker.rb index a5202b26..c3ceca62 100644 --- a/app/models/tracker.rb +++ b/app/models/tracker.rb @@ -1,4 +1,16 @@ +# == Schema Information +# +# Table name: trackers +# +# id :integer not null, primary key +# name :string(30) default(""), not null +# is_in_chlog :boolean default("0"), not null +# position :integer default("1") +# is_in_roadmap :boolean default("1"), not null +# fields_bits :integer default("0") +# + class Tracker < ApplicationRecord has_many :issues has_and_belongs_to_many :projects -end \ No newline at end of file +end diff --git a/app/models/user.rb b/app/models/user.rb index ee61fdb9..0797c78d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,67 @@ +# == Schema Information +# +# Table name: users +# +# id :integer not null, primary key +# login :string(255) default(""), not null +# hashed_password :string(40) default(""), not null +# firstname :string(30) default(""), not null +# lastname :string(255) default(""), not null +# mail :string(60) +# admin :boolean default("0"), not null +# status :integer default("1"), not null +# last_login_on :datetime +# language :string(5) default("") +# auth_source_id :integer +# created_on :datetime +# updated_on :datetime +# type :string(255) +# identity_url :string(255) +# mail_notification :string(255) default(""), not null +# salt :string(64) +# gid :integer +# visits :integer default("0") +# excellent_teacher :integer default("0") +# excellent_student :integer default("0") +# phone :string(255) +# authentication :boolean default("0") +# grade :integer default("0") +# experience :integer default("0") +# nickname :string(255) +# show_realname :boolean default("1") +# professional_certification :boolean default("0") +# ID_number :string(255) +# certification :integer default("0") +# homepage_teacher :boolean default("0") +# homepage_engineer :boolean default("0") +# is_test :integer default("0") +# ecoder_user_id :integer default("0") +# business :boolean default("0") +# profile_completed :boolean default("0") +# laboratory_id :integer +# platform :string(255) default("0") +# gitea_token :string(255) +# gitea_uid :integer +# is_shixun_marker :boolean default("0") +# is_sync_pwd :boolean default("1") +# watchers_count :integer default("0") +# visibility :string(255) default("public") +# repo_admin_change_team_access :boolean default("1") +# is_org :boolean default("0") +# website :string(255) +# devops_step :integer default("0") +# +# Indexes +# +# index_users_on_ecoder_user_id (ecoder_user_id) +# index_users_on_homepage_engineer (homepage_engineer) +# index_users_on_homepage_teacher (homepage_teacher) +# index_users_on_laboratory_id (laboratory_id) +# index_users_on_login (login) +# index_users_on_mail (mail) +# index_users_on_type (type) +# + class User < ApplicationRecord extend Enumerize @@ -5,8 +69,16 @@ class User < ApplicationRecord include Likeable include BaseModel include ProjectOperable + include ProjectAbility + include Droneable # include Searchable::Dependents::User + # devops step + # devops_step column: 0: 未填写服务器信息;1: 已填写服务器信息(未认证);2: 已认证 + DEVOPS_UNINIT = 0 + DEVOPS_UNVERIFIED = 1 + DEVOPS_CERTIFICATION = 2 + # Account statuses STATUS_ANONYMOUS = 0 STATUS_ACTIVE = 1 @@ -70,8 +142,9 @@ class User < ApplicationRecord # 关注 has_many :be_watchers, foreign_key: :user_id, dependent: :destroy # 我的关注 has_many :be_watcher_users, through: :be_watchers, dependent: :destroy # 我关注的用户 - - has_many :watchers, as: :watchable, dependent: :destroy + has_many :watchers, as: :watchable, dependent: :destroy + + has_one :ci_cloud_account, class_name: 'Ci::CloudAccount', dependent: :destroy # 认证 has_many :apply_user_authentication @@ -91,6 +164,7 @@ class User < ApplicationRecord # 教学案例 # has_many :libraries, dependent: :destroy has_many :project_trends, dependent: :destroy + has_many :oauths , dependent: :destroy # sponsor has_many :as_sponsors, class_name: 'Sponsorship', foreign_key: 'sponsor_id', dependent: :destroy @@ -515,7 +589,7 @@ class User < ApplicationRecord def self.anonymous anonymous_user = AnonymousUser.unscoped.take if anonymous_user.nil? - anonymous_user = AnonymousUser.unscoped.create(lastname: 'Anonymous', firstname: '', login: '', mail: '358551897@qq.com', phone: '13333333333', status: 0, platform: User.platform[:forge]) + anonymous_user = AnonymousUser.unscoped.create(lastname: 'Anonymous', firstname: '', login: '', mail: '358551897@qq.com', phone: '13333333333', status: 0, platform: User.platform.forge) raise "Unable to create the anonymous user: error_info:#{anonymous_user.errors.messages}" if anonymous_user.new_record? end anonymous_user diff --git a/app/models/user_action.rb b/app/models/user_action.rb index d3d70a66..3ad8010e 100644 --- a/app/models/user_action.rb +++ b/app/models/user_action.rb @@ -1,2 +1,19 @@ +# == Schema Information +# +# Table name: user_actions +# +# id :integer not null, primary key +# user_id :integer +# action_type :string(255) +# action_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# ip :string(255) +# +# Indexes +# +# index_user_actions_on_ip (ip) +# + class UserAction < ApplicationRecord end diff --git a/app/models/user_agent.rb b/app/models/user_agent.rb index ebe7ed03..49d7b35a 100644 --- a/app/models/user_agent.rb +++ b/app/models/user_agent.rb @@ -1,3 +1,21 @@ +# == Schema Information +# +# Table name: user_agents +# +# id :integer not null, primary key +# agent_type :string(255) +# key :string(255) +# ip :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# register_status :integer default("0") +# action_status :integer default("0") +# +# Indexes +# +# index_user_agents_on_ip (ip) UNIQUE +# + class UserAgent < ApplicationRecord has_many :user_actions, :foreign_key => "ip", :primary_key => "ip" USER_AD = 1 # 广告宣传的引流 diff --git a/app/models/user_day_certification.rb b/app/models/user_day_certification.rb index 18da0fd1..ccf26a2f 100644 --- a/app/models/user_day_certification.rb +++ b/app/models/user_day_certification.rb @@ -1,2 +1,17 @@ +# == Schema Information +# +# Table name: user_day_certifications +# +# id :integer not null, primary key +# user_id :integer +# status :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_user_day_certifications_on_user_id (user_id) +# + class UserDayCertification < ApplicationRecord end diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 0a3c7368..20e2b5c4 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -1,3 +1,35 @@ +# == Schema Information +# +# Table name: user_extensions +# +# id :integer not null, primary key +# user_id :integer not null +# birthday :date +# brief_introduction :string(255) +# gender :integer +# location :string(255) +# occupation :string(255) +# work_experience :integer +# zip_code :integer +# created_at :datetime not null +# updated_at :datetime not null +# technical_title :string(255) +# identity :integer +# student_id :string(255) +# teacher_realname :string(255) +# student_realname :string(255) +# location_city :string(255) +# school_id :integer +# description :string(255) default("") +# department_id :integer +# +# Indexes +# +# index_user_extensions_on_department_id (department_id) +# index_user_extensions_on_school_id_and_user_id (school_id,user_id) +# index_user_extensions_on_user_id (user_id) +# + class UserExtension < ApplicationRecord # identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者 enum identity: { teacher: 0, student: 1, professional: 2, developer: 3, enterprise: 4, unselect: -1 } diff --git a/app/models/user_grade.rb b/app/models/user_grade.rb index af7490ed..970392b1 100644 --- a/app/models/user_grade.rb +++ b/app/models/user_grade.rb @@ -1,3 +1,21 @@ +# == Schema Information +# +# Table name: user_grades +# +# id :integer not null, primary key +# user_id :integer not null +# project_id :integer not null +# grade :float(24) default("0") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_user_grades_on_grade (grade) +# index_user_grades_on_project_id (project_id) +# index_user_grades_on_user_id (user_id) +# + class UserGrade < ApplicationRecord # belongs_to :project # belongs_to :user diff --git a/app/models/user_interest.rb b/app/models/user_interest.rb index 1c2d8bc8..ae553812 100644 --- a/app/models/user_interest.rb +++ b/app/models/user_interest.rb @@ -1,4 +1,18 @@ +# == Schema Information +# +# Table name: user_interests +# +# id :integer not null, primary key +# user_id :integer +# repertoire_id :integer +# +# Indexes +# +# index_user_interests_on_repertoire_id (repertoire_id) +# index_user_interests_on_user_id (user_id) +# + class UserInterest < ApplicationRecord belongs_to :user # belongs_to :repertoire -end \ No newline at end of file +end diff --git a/app/models/verification_code.rb b/app/models/verification_code.rb index 452e637a..a71d9018 100644 --- a/app/models/verification_code.rb +++ b/app/models/verification_code.rb @@ -1,3 +1,22 @@ +# == Schema Information +# +# Table name: verification_codes +# +# id :integer not null, primary key +# code :string(255) +# code_type :integer +# status :integer +# phone :string(255) +# email :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# by_email (email) +# by_phone (phone) +# + class VerificationCode < ApplicationRecord def effective? created_at + 10.minute > Time.current diff --git a/app/models/version.rb b/app/models/version.rb index 18996d6c..bee22cd5 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -1,3 +1,28 @@ +# == Schema Information +# +# Table name: versions +# +# id :integer not null, primary key +# project_id :integer default("0"), not null +# name :string(255) default(""), not null +# description :text(65535) +# effective_date :date +# created_on :datetime +# updated_on :datetime +# wiki_page_title :string(255) +# status :string(255) default("open") +# sharing :string(255) default("none"), not null +# user_id :integer +# issues_count :integer default("0") +# closed_issues_count :integer default("0") +# percent :float(24) default("0") +# +# Indexes +# +# index_versions_on_sharing (sharing) +# versions_project_id (project_id) +# + class Version < ApplicationRecord belongs_to :project, counter_cache: true has_many :issues, class_name: "Issue", foreign_key: "fixed_version_id" diff --git a/app/models/version_release.rb b/app/models/version_release.rb index 7d733fb1..16b823a7 100644 --- a/app/models/version_release.rb +++ b/app/models/version_release.rb @@ -1,3 +1,28 @@ +# == Schema Information +# +# Table name: version_releases +# +# id :integer not null, primary key +# user_id :integer +# name :string(255) +# body :text(65535) +# tag_name :string(255) +# target_commitish :string(255) +# draft :boolean default("0") +# prerelease :boolean default("0") +# tarball_url :string(255) +# zipball_url :string(255) +# url :string(255) +# version_gid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# repository_id :integer +# +# Indexes +# +# index_version_releases_on_repository_id (repository_id) +# + class VersionRelease < ApplicationRecord belongs_to :repository, counter_cache: true belongs_to :user diff --git a/app/models/watcher.rb b/app/models/watcher.rb index 50bd7580..76a82702 100644 --- a/app/models/watcher.rb +++ b/app/models/watcher.rb @@ -1,3 +1,20 @@ +# == Schema Information +# +# Table name: watchers +# +# id :integer not null, primary key +# watchable_type :string(255) default(""), not null +# watchable_id :integer default("0"), not null +# user_id :integer +# created_at :datetime +# +# Indexes +# +# index_watchers_on_user_id (user_id) +# index_watchers_on_watchable_id_and_watchable_type (watchable_id,watchable_type) +# watchers_user_id_type (user_id,watchable_type) +# + class Watcher < ApplicationRecord belongs_to :user diff --git a/app/models/weapp_setting.rb b/app/models/weapp_setting.rb index a4ef86eb..ed80acd0 100644 --- a/app/models/weapp_setting.rb +++ b/app/models/weapp_setting.rb @@ -1,3 +1,16 @@ +# == Schema Information +# +# Table name: weapp_settings +# +# id :integer not null, primary key +# type :string(255) +# link :string(255) +# online :boolean default("0") +# position :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# + class WeappSetting < ApplicationRecord scope :only_online, -> { where(online: true) } -end \ No newline at end of file +end diff --git a/app/models/weapp_settings/advert.rb b/app/models/weapp_settings/advert.rb index 993b1fd8..209b144e 100644 --- a/app/models/weapp_settings/advert.rb +++ b/app/models/weapp_settings/advert.rb @@ -1,3 +1,16 @@ +# == Schema Information +# +# Table name: weapp_settings +# +# id :integer not null, primary key +# type :string(255) +# link :string(255) +# online :boolean default("0") +# position :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# + class WeappSettings::Advert < WeappSetting default_scope { order(position: :asc) } -end \ No newline at end of file +end diff --git a/app/models/weapp_settings/carousel.rb b/app/models/weapp_settings/carousel.rb index 71445fd3..4f914882 100644 --- a/app/models/weapp_settings/carousel.rb +++ b/app/models/weapp_settings/carousel.rb @@ -1,3 +1,16 @@ +# == Schema Information +# +# Table name: weapp_settings +# +# id :integer not null, primary key +# type :string(255) +# link :string(255) +# online :boolean default("0") +# position :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# + class WeappSettings::Carousel < WeappSetting default_scope { order(position: :asc) } -end \ No newline at end of file +end diff --git a/app/queries/ci/builds/list_query.rb b/app/queries/ci/builds/list_query.rb new file mode 100644 index 00000000..bfb0b0a5 --- /dev/null +++ b/app/queries/ci/builds/list_query.rb @@ -0,0 +1,29 @@ +class Ci::Builds::ListQuery < ApplicationQuery + include CustomSortable + + attr_reader :params + + sort_columns :build_created, default_by: :build_created, default_direction: :desc + + def initialize(repo, params) + @repo = repo + @params = params + end + + def call + scope = @repo.builds + + builds = + case params[:search] + when 'success' then scope.successed + when 'pending' then scope.pending + when 'error' then scope.errored + when 'running' then scope.running + when 'failure' then scope.failed + when 'killed' then scope.killed + else + scope + end + custom_sort(builds, params[:sort_by], params[:sort_direction]) + end +end diff --git a/app/queries/projects/list_query.rb b/app/queries/projects/list_query.rb index 91a2a762..04f1d168 100644 --- a/app/queries/projects/list_query.rb +++ b/app/queries/projects/list_query.rb @@ -10,10 +10,9 @@ class Projects::ListQuery < ApplicationQuery end def call - q = Project.visible.search_project(params[:search]) + q = Project.visible.by_name_or_identifier(params[:search]) - scope = q.result(distinct: true) - .includes(:project_category, :project_language, :repository, owner: :user_extension) + scope = q .with_project_type(params[:project_type]) .with_project_category(params[:category_id]) .with_project_language(params[:language_id]) @@ -21,7 +20,9 @@ class Projects::ListQuery < ApplicationQuery sort = params[:sort_by] || "updated_on" sort_direction = params[:sort_direction] || "desc" - scope = scope.no_anomory_projects.reorder("projects.#{sort} #{sort_direction}") - scope + custom_sort(scope, sort, sort_direction) + + # scope = scope.reorder("projects.#{sort} #{sort_direction}") + # scope end end diff --git a/app/services/educoder/client_service.rb b/app/services/educoder/client_service.rb new file mode 100644 index 00000000..6c5c10d9 --- /dev/null +++ b/app/services/educoder/client_service.rb @@ -0,0 +1,112 @@ +class Educoder::ClientService < ApplicationService + attr_reader :url, :params + + PAGINATE_DEFAULT_PAGE = 1 + PAGINATE_DEFAULT_LIMIT = 20 + + def initialize(options={}) + @url = options[:url] + @params = options[:params] + end + + def post(url, params={}) + puts "[educoder] request params: #{params}" + auth_token = authen_params(params[:token]) + response = conn(auth_token).post do |req| + req.url full_url(url) + req.body = params[:data].to_json + end + render_status(response) + end + + def get(url, params={}) + puts "[educoder] params: #{params}" + conn(api_url(url), params) + end + + def delete(url, params={}) + auth_token = authen_params(params[:token]) + conn(auth_token).delete do |req| + req.url full_url(url) + req.body = params[:data].to_json + end + end + + def patch(url, params={}) + puts "[educoder] request params: #{params}" + auth_token = authen_params(params[:token]) + conn(auth_token).patch do |req| + req.url full_url(url) + req.body = params[:data].to_json + end + end + + def put(url, params={}) + puts "[educoder] put request params: #{params}" + conn(authen_params(params[:token])).put do |req| + req.url full_url(url) + req.body = params[:data].to_json + end + end + + private + def conn(url, hash={}) + par = [] + hash.each do |k,v| + par << "#{k}=#{v}" + end + + uri = URI("#{url}.json?#{par.join('&')}&private_token=#{private_token}") + puts "[educoder] request_url: #{uri}" + response = Net::HTTP.get_response(uri) + puts "[educoder] response code: #{response.code.to_i}" + if response.code.to_i != 200 + puts "======= 接口请求失败!" + raise '接口请求失败.' + return nil + end + JSON.parse(response.body) + end + + def base_url + Rails.application.config_for(:configuration)['educoder']['base_url'] + end + + def domain + Rails.application.config_for(:configuration)['educoder']['main_site'] + end + + def private_token + Rails.application.config_for(:configuration)['educoder']['token'] + end + + def access_key_secret + Gitea.gitea_config[:access_key_secret] + end + + def api_url(url) + [domain, base_url, url].join('/') + end + + def full_url(api_rest, action='post') + url = [api_url, api_rest].join('').freeze + url = action === 'get' ? url : URI.escape(url) + puts "[gitea] request url: #{url}" + return url + end + + + + def authen_params(token) + (token.is_a? String) ? {token: token} : Hash(token) + end + + def render_data(response) + case response.status + when 201, 200 + JSON.parse(response.body) + else + nil + end + end +end diff --git a/app/services/educoder/repository/commits/list_service.rb b/app/services/educoder/repository/commits/list_service.rb new file mode 100644 index 00000000..1a83c260 --- /dev/null +++ b/app/services/educoder/repository/commits/list_service.rb @@ -0,0 +1,29 @@ +class Educoder::Repository::Commits::ListService < Educoder::ClientService + attr_reader :repo_name, :args + + # ref: The name of the commit/branch/tag. Default the repository’s default branch (usually master) + # repo_name: the name of repository + # Educoder::Repository::Commits::ListService.call('fessf/6hiwcb7o20200917174054') + def initialize(repo_name, **args) + @repo_name = repo_name + @args = {ref: 'master'}.merge(args.compact) + end + + def call + response = get(url, params) + render_result(response) + end + + private + def params + @args.merge(repo_name: repo_name) + end + + def url + "commits".freeze + end + + def render_result(response) + response['commits'] || [] + end +end diff --git a/app/services/educoder/repository/entries/get_service.rb b/app/services/educoder/repository/entries/get_service.rb new file mode 100644 index 00000000..9c4fed92 --- /dev/null +++ b/app/services/educoder/repository/entries/get_service.rb @@ -0,0 +1,30 @@ +class Educoder::Repository::Entries::GetService < Educoder::ClientService + attr_reader :repo_name, :filepath + + # filepath: path of the dir, file, symlink or submodule in the repo + # repo_name: the name of repository + def initialize(repo_name, filepath) + @repo_name = repo_name + @filepath = filepath + end + + def call + get(url, params) + end + + private + def params + Hash.new.merge(repo_name: repo_name, path: filepath) + end + + def url + "file_content".freeze + end + + def render_result(response) + body = JSON.parse(response.body) + if body['status'].to_i === -1 + raise '无权限访问.' + end + end +end diff --git a/app/services/educoder/repository/entries/list_service.rb b/app/services/educoder/repository/entries/list_service.rb new file mode 100644 index 00000000..dd3abea7 --- /dev/null +++ b/app/services/educoder/repository/entries/list_service.rb @@ -0,0 +1,39 @@ +class Educoder::Repository::Entries::ListService < Educoder::ClientService + attr_reader :repo_name, :args + + # ref: The name of the commit/branch/tag. Default the repository’s default branch (usually master) + # repo_name: the name of repository + # args: + # { + # "repo_name": "wmov43ez8/5xahe2t7nv20191022173304", + # "path": 'src' + # } + # Educoder::Repository::Entries::ListService.new('wmov43ez8/5xahe2t7nv20191022173304', {path: 'src'}).call + def initialize(repo_name, args={}) + @repo_name = repo_name + @args = args.compact + end + + def call + get(url, params) + end + + private + def params + @args.merge(repo_name: repo_name) + end + + def url + "repository".freeze + end + + def render_result(response) + body = JSON.parse(response.body) + case response.status + when 200 + body + else + [] + end + end +end diff --git a/app/services/gitea/chain/chain_get_service.rb b/app/services/gitea/chain/chain_get_service.rb new file mode 100644 index 00000000..3ac1bff7 --- /dev/null +++ b/app/services/gitea/chain/chain_get_service.rb @@ -0,0 +1,29 @@ +class Gitea::Chain::ChainGetService < Gitea::ChainService + + attr_reader :params + + def initialize(params) + @params = params + end + + def call + get(url, request_params) + end + + private + + def request_params + params[:chain_params] + end + + def url + chain_type = params[:type].to_s + case chain_type + when "query" + "/repos/amount/query".freeze + else + "".freeze + end + end + +end \ No newline at end of file diff --git a/app/services/gitea/chain/chain_post_service.rb b/app/services/gitea/chain/chain_post_service.rb new file mode 100644 index 00000000..3ce1a2cb --- /dev/null +++ b/app/services/gitea/chain/chain_post_service.rb @@ -0,0 +1,31 @@ +class Gitea::Chain::ChainPostService < Gitea::ChainService + + attr_reader :params + + def initialize(params) + @params = params + end + + def call + post(url, request_params) + end + + private + + def request_params + Hash.new.merge(data: params[:chain_params]) + end + + def url + chain_type = params[:type].to_s + case chain_type + when "create" + "/repos/create".freeze + when "upload" + "/repos/commit/upload".freeze + else #由于目前的api文档操作post请求,除了create/upload,都是在/repos/amount/*,所以以下简化了 + "/repos/amount/#{chain_type}".freeze + end + end + +end \ No newline at end of file diff --git a/app/services/gitea/chain_service.rb b/app/services/gitea/chain_service.rb new file mode 100644 index 00000000..9e161226 --- /dev/null +++ b/app/services/gitea/chain_service.rb @@ -0,0 +1,49 @@ +class Gitea::ChainService < ApplicationService + attr_reader :url, :params + + def initialize(options={}) + @url = options[:url] + @params = options[:params] + end + + def post(url, params={}) + Rails.logger.info("######_____api____request_url_______###############{request_url}") + Rails.logger.info("######_____api____request_params_______###############{params}") + + conn.post do |req| + req.url "#{request_url}" + req.body = params[:data].to_json + end + end + + def get(url, params={}) + conn.get do |req| + req.url "#{request_url}" + params.each_pair do |key, value| + req.params["#{key}"] = value + end + end + end + + private + def conn(auth={}) + @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 + end + end + @client + end + + def domain + Rails.application.config_for(:configuration)['chain_base'] + end + + def request_url + [domain, url].join('').freeze + end + +end diff --git a/app/services/gitea/client_service.rb b/app/services/gitea/client_service.rb index 58427637..1ccd3350 100644 --- a/app/services/gitea/client_service.rb +++ b/app/services/gitea/client_service.rb @@ -20,13 +20,9 @@ class Gitea::ClientService < ApplicationService # } def post(url, params={}) puts "[gitea] request params: #{params}" - request_url = [api_url, url].join('').freeze - Rails.logger.info("######_____api____request_url_______###############{request_url}") - Rails.logger.info("######_____api____request_params_______###############{params}") - auth_token = authen_params(params[:token]) response = conn(auth_token).post do |req| - req.url "#{request_url}" + req.url full_url(url) req.body = params[:data].to_json end render_status(response) @@ -35,7 +31,7 @@ class Gitea::ClientService < ApplicationService def get(url, params={}) auth_token = authen_params(params[:token]) conn(auth_token).get do |req| - req.url full_url(url) + req.url full_url(url, 'get') params.except(:token).each_pair do |key, value| req.params["#{key}"] = value end @@ -73,9 +69,10 @@ class Gitea::ClientService < ApplicationService private def conn(auth={}) - username = auth[:username] || access_key_id - secret = auth[:password] || access_key_secret + username = auth[:username] + secret = auth[:password] token = auth[:token] + puts "[gitea] username: #{username}" puts "[gitea] secret: #{secret}" puts "[gitea] token: #{token}" @@ -105,26 +102,19 @@ class Gitea::ClientService < ApplicationService Gitea.gitea_config[:domain] end - def access_key_id - Gitea.gitea_config[:access_key_id] - end - - def access_key_secret - Gitea.gitea_config[:access_key_secret] - end - def api_url [domain, base_url].join('') end - def full_url(api_rest) - [api_url, api_rest].join('').freeze + def full_url(api_rest, action='post') + url = [api_url, api_rest].join('').freeze + url = action === 'get' ? url : URI.escape(url) + puts "[gitea] request url: #{url}" + return url end def render_status(response) - Rails.logger.info("###############____response__#{response}") - Rails.logger.info("###############____response_status_#{response.status}") - Rails.logger.info("###############____response_body_#{response.body}") + puts "[gitea] response status: #{response.status}" mark = "[gitea] " case response.status when 201, 200, 202 @@ -134,13 +124,12 @@ class Gitea::ClientService < ApplicationService {status: 200} end when 401 - "" raise Error, mark + "401" when 422 result = JSON.parse(response&.body) - puts "[gitea] parse body: #{result}" + puts "[gitea] parse body: #{result['message']}" # return {status: -1, message: result[0]} - raise Error, result[0] + raise Error, result['message'] when 204 puts "[gitea] " @@ -150,6 +139,8 @@ class Gitea::ClientService < ApplicationService raise Error, mark + message when 403 {status: 403, message: '你没有权限操作!'} + when 404 + {status: 404, message: '你访问的链接不存在!'} else if response&.body.blank? message = "请求失败" diff --git a/app/services/gitea/hooks/create_service.rb b/app/services/gitea/hooks/create_service.rb index 9c66c9a7..711427e2 100644 --- a/app/services/gitea/hooks/create_service.rb +++ b/app/services/gitea/hooks/create_service.rb @@ -1,23 +1,39 @@ class Gitea::Hooks::CreateService < Gitea::ClientService - attr_reader :user, :repo_name, :body + attr_reader :token, :owner, :repo, :body - def initialize(user, repo_name, body) - @user = user - @repo_name = repo_name - @body = body + # body params: + # { + # "active": false, + # "branch_filter": "string", + # "config": { + # "content_type": "string", + # "url": "string" + # }, + # "events": [ + # "create" + # ], + # "type": "gitea" + # } + # eg: + # Gitea::Hooks::CreateService.call(user.gitea_token, user.login, repo.identifier, body) + def initialize(token, owner, repo, body) + @token = token + @owner = owner + @repo = repo + @body = body end - def call - response = post(url, params) + def call + post(url, params) end private def params - body.merge(token: user.gitea_token) + Hash.new.merge(token: token, data: body).compact end def url - "/repos/#{user.login}/#{repo_name}/hooks".freeze + "/repos/#{owner}/#{repo}/hooks".freeze end -end \ No newline at end of file +end diff --git a/app/services/gitea/hooks/destroy_service.rb b/app/services/gitea/hooks/destroy_service.rb index 779ebd41..b30178ea 100644 --- a/app/services/gitea/hooks/destroy_service.rb +++ b/app/services/gitea/hooks/destroy_service.rb @@ -1,23 +1,23 @@ class Gitea::Hooks::DestroyService < Gitea::ClientService - attr_reader :user, :repo_name,:hook_id + attr_reader :token, :owner, :repo, :hook_id - def initialize(user, repo_name, hook_id) - @user = user - @repo_name = repo_name + def initialize(token, owner, repo, hook_id) + @token = token + @owner = owner + @repo = repo @hook_id = hook_id end - def call - response = delete(url, params) + def call + delete(url, params) end private def params - Hash.new.merge(token: user.gitea_token) + Hash.new.merge(token: token) end def url - "/repos/#{user.login}/#{repo_name}/hooks/#{hook_id}".freeze + "/repos/#{owner}/#{repo}/hooks/#{hook_id}".freeze end - -end \ No newline at end of file +end diff --git a/app/services/gitea/hooks/list_service.rb b/app/services/gitea/hooks/list_service.rb index 00170073..3bd05ea5 100644 --- a/app/services/gitea/hooks/list_service.rb +++ b/app/services/gitea/hooks/list_service.rb @@ -1,23 +1,27 @@ class Gitea::Hooks::ListService < Gitea::ClientService - attr_reader :user, :repo_name + attr_reader :token, :owner, :repo, :params - def initialize(user, repo_name) - @user = user - @repo_name = repo_name - @body = body + def initialize(token, owner, repo_name, params={}) + @token = token + @owner = owner + @repo = repo + @params = params end - def call - response = get(url, params) + def call + get(url, params) end private def params - Hash.new.merge(token: user.gitea_token) + Hash.new.merge(token: token, + page: params[:page], + limit: params[:limit] + ).compact end def url - "/repos/#{user.login}/#{repo_name}/hooks".freeze + "/repos/#{owner}/#{repo}/hooks".freeze end -end \ No newline at end of file +end diff --git a/app/services/gitea/hooks/update_service.rb b/app/services/gitea/hooks/update_service.rb index d5946758..9086a3a3 100644 --- a/app/services/gitea/hooks/update_service.rb +++ b/app/services/gitea/hooks/update_service.rb @@ -2,14 +2,14 @@ class Gitea::Hooks::UpdateService < Gitea::ClientService attr_reader :user, :repo_name, :body,:hook_id def initialize(user, repo_name, body, hook_id) - @user = user - @repo_name = repo_name - @body = body + @user = user + @repo_name = repo_name + @body = body @hook_id = hook_id end - def call - response = patch(url, params) + def call + patch(url, params) end private @@ -21,4 +21,4 @@ class Gitea::Hooks::UpdateService < Gitea::ClientService "/repos/#{user.login}/#{repo_name}/hooks/#{hook_id}".freeze end -end \ No newline at end of file +end diff --git a/app/services/gitea/oauth2/create_service.rb b/app/services/gitea/oauth2/create_service.rb new file mode 100644 index 00000000..ba87e960 --- /dev/null +++ b/app/services/gitea/oauth2/create_service.rb @@ -0,0 +1,41 @@ +# creates a new OAuth2 application +class Gitea::Oauth2::CreateService < Gitea::ClientService + attr_reader :token, :params + + # params: + # { + # "name": "string", + # "redirect_uris": [ + # "string" + # ] + # } + # ep: Gitea::OAuth2::CreateService.call(current_user.gitea_token, {name: 'oauth_name', redirect_uris: ['url']}) + # return values example: + # { + # "client_id": "string", + # "client_secret": "string", + # "created": "2020-07-08T03:12:49.960Z", + # "id": 0, + # "name": "string", + # "redirect_uris": [ + # "string" + # ] + # } + def initialize(token, params) + @token = token + @params = params + end + + def call + post(url, request_params) + end + + private + def url + "/user/applications/oauth2".freeze + end + + def request_params + params.merge(token: token, data: params).compact + end +end diff --git a/app/services/gitea/pull_request/commits_service.rb b/app/services/gitea/pull_request/commits_service.rb new file mode 100644 index 00000000..aca2067c --- /dev/null +++ b/app/services/gitea/pull_request/commits_service.rb @@ -0,0 +1,40 @@ +# List commits on a pull request +class Gitea::PullRequest::CommitsService < Gitea::ClientService + attr_reader :owner, :repo, :pull_number, :token + + # GET /repos/{owner}/{repo}/pulls/{pull_number}/commits + # owner: 用户 + # repo: 仓库名称/标识 + # pull_number: pull request主键id + # eg: + # Gitea::PullRequest::FilesService.call('jasder', 'repo_identifier', 1) + def initialize(owner, repo, pull_number, token=nil) + @owner = owner + @repo = repo + @token = token + @pull_number = pull_number + end + + def call + response = get(url, params) + render_result(response) + end + + private + def params + Hash.new.merge(token: owner) + end + + def url + "/repos/#{owner}/#{repo}/pulls/#{pull_number}/commits".freeze + end + + def render_result(response) + case response.status + when 200 + JSON.parse(response.body) + else + nil + end + end +end diff --git a/app/services/gitea/pull_request/files_service.rb b/app/services/gitea/pull_request/files_service.rb new file mode 100644 index 00000000..9785588e --- /dev/null +++ b/app/services/gitea/pull_request/files_service.rb @@ -0,0 +1,40 @@ +# List pull requests files +class Gitea::PullRequest::FilesService < Gitea::ClientService + attr_reader :owner, :repo, :pull_number, :token + + # GET /repos/{owner}/{repo}/pulls/{pull_number}/files + # owner: 用户 + # repo: 仓库名称/标识 + # pull_number: pull request主键id + # eg: + # Gitea::PullRequest::FilesService.call('jasder', 'repo_identifier', 1) + def initialize(owner, repo, pull_number, token=nil) + @owner = owner + @repo = repo + @token = token + @pull_number = pull_number + end + + def call + response = get(url, params) + render_result(response) + end + + private + def params + Hash.new.merge(token: token) + end + + def url + "/repos/#{owner}/#{repo}/pulls/#{pull_number}/files".freeze + end + + def render_result(response) + case response.status + when 200 + JSON.parse(response.body) + else + nil + end + end +end diff --git a/app/services/gitea/repository/commits/compare_service.rb b/app/services/gitea/repository/commits/compare_service.rb new file mode 100644 index 00000000..502f6ce9 --- /dev/null +++ b/app/services/gitea/repository/commits/compare_service.rb @@ -0,0 +1,29 @@ +# Compare two commits +class Gitea::Repository::Commits::CompareService < Gitea::ClientService + attr_reader :owner, :repo, :base, :head, :token + + # sha: the commit hash + # ex: + # Gitea::Repository::Commits::CompareService.call('owner', 'repo_identifier', 'master', 'jasder/repo_identifier:develop') + def initialize(owner, repo, base, head, token=nil) + @token = token + @owner = owner + @base = base + @repo = repo + @head = head + end + + def call + response = get(url, params) + render_status(response) + end + + private + def params + Hash.new.merge(token: token) + end + + def url + "/repos/#{owner}/#{repo}/compare/#{base}...#{head}".freeze + end +end diff --git a/app/services/gitea/repository/commits/get_service.rb b/app/services/gitea/repository/commits/get_service.rb index 019658d1..d497f1e4 100644 --- a/app/services/gitea/repository/commits/get_service.rb +++ b/app/services/gitea/repository/commits/get_service.rb @@ -1,21 +1,21 @@ # Get a single commit from a repository class Gitea::Repository::Commits::GetService < Gitea::ClientService - attr_reader :token, :owner, :repo, :sha, :custom + attr_reader :token, :owner, :repo, :sha, :hash # sha: the commit hash # ex: Gitea::Repository::Commits::GetService.new(@repo.user.login, repo.identifier, params[:sha], current_user.gitea_token) # TODO custom参数用于判断调用哪个api - def initialize(owner, repo, sha, token, custom=false) + def initialize(owner, repo, sha, token, hash={}) @token = token @owner = owner @sha = sha @repo = repo - @custom = custom + @hash = hash end def call response = get(url, params) - render_result(response) + render_status(response) end private @@ -24,22 +24,12 @@ class Gitea::Repository::Commits::GetService < Gitea::ClientService end def url - if custom + if hash[:diff] # TODO # 平台自己编写的gitea接口,后续可能会通过提交pr的形式合并到gitea原有的接口上 - "/repos/#{owner}/#{repo}/commits/diff/#{sha}".freeze + "/repos/#{owner}/#{repo}/commits/#{sha}/diff".freeze else "/repos/#{owner}/#{repo}/git/commits/#{sha}".freeze end end - - def render_result(response) - body = JSON.parse(response.body) - case response.status - when 200 - JSON.parse(response.body) - else - {status: -1, message: "#{body['message']}"} - end - end end diff --git a/app/services/gitea/repository/entries/create_service.rb b/app/services/gitea/repository/entries/create_service.rb index 62514fad..7f1a6b52 100644 --- a/app/services/gitea/repository/entries/create_service.rb +++ b/app/services/gitea/repository/entries/create_service.rb @@ -1,5 +1,5 @@ class Gitea::Repository::Entries::CreateService < Gitea::ClientService - attr_reader :user, :repo_name, :filepath, :body + attr_reader :token, :owner, :repo_name, :filepath, :body # ref: The name of the commit/branch/tag. Default the repository’s default branch (usually master) # filepath: path of the dir, file, symlink or submodule in the repo @@ -20,8 +20,9 @@ class Gitea::Repository::Entries::CreateService < Gitea::ClientService # "new_branch": "string" # } # - def initialize(user, repo_name, filepath, body) - @user = user + def initialize(token, owner, repo_name, filepath, body) + @token = token + @owner = owner @repo_name = repo_name @filepath = filepath @body = body @@ -33,11 +34,11 @@ class Gitea::Repository::Entries::CreateService < Gitea::ClientService private def params - Hash.new.merge(token: user.gitea_token, data: body) + Hash.new.merge(token: token, data: body) end def url - "/repos/#{user.login}/#{repo_name}/contents/#{filepath}".freeze + "/repos/#{owner}/#{repo_name}/contents/#{filepath}".freeze end end diff --git a/app/services/gitea/repository/entries/delete_service.rb b/app/services/gitea/repository/entries/delete_service.rb index cfc79a5b..f9f41290 100644 --- a/app/services/gitea/repository/entries/delete_service.rb +++ b/app/services/gitea/repository/entries/delete_service.rb @@ -1,5 +1,5 @@ class Gitea::Repository::Entries::DeleteService < Gitea::ClientService - attr_reader :user, :repo_name, :filepath, :body + attr_reader :token, :owner, :repo_name, :filepath, :body # ref: The name of the commit/branch/tag. Default the repository’s default branch (usually master) # filepath: path of the dir, file, symlink or submodule in the repo @@ -19,8 +19,9 @@ class Gitea::Repository::Entries::DeleteService < Gitea::ClientService # "new_branch": "string", # "sha": "string", #require # } - def initialize(user, repo_name, filepath, body) - @user = user + def initialize(token, owner, repo_name, filepath, body) + @token = token + @owner = owner @repo_name = repo_name @filepath = filepath @body = body @@ -32,11 +33,11 @@ class Gitea::Repository::Entries::DeleteService < Gitea::ClientService private def params - Hash.new.merge(token: user.gitea_token, data: body) + Hash.new.merge(token: token, data: body) end def url - "/repos/#{user.login}/#{repo_name}/contents/#{filepath}".freeze + "/repos/#{owner}/#{repo_name}/contents/#{filepath}".freeze end end diff --git a/app/services/gitea/repository/entries/get_service.rb b/app/services/gitea/repository/entries/get_service.rb index f0236a07..f8ac2754 100644 --- a/app/services/gitea/repository/entries/get_service.rb +++ b/app/services/gitea/repository/entries/get_service.rb @@ -31,8 +31,10 @@ class Gitea::Repository::Entries::GetService < Gitea::ClientService case response.status when 200 body + when 404 + raise '你访问的文件不存在' else - {status: -1, message: "#{body['message']}"} + raise body['message'] end end end diff --git a/app/services/gitea/repository/entries/update_service.rb b/app/services/gitea/repository/entries/update_service.rb index 3f0ddf94..dadabc38 100644 --- a/app/services/gitea/repository/entries/update_service.rb +++ b/app/services/gitea/repository/entries/update_service.rb @@ -1,5 +1,5 @@ class Gitea::Repository::Entries::UpdateService < Gitea::ClientService - attr_reader :user, :repo_name, :filepath, :body + attr_reader :token, :owner, :repo_name, :filepath, :body # ref: The name of the commit/branch/tag. Default the repository’s default branch (usually master) # filepath: path of the dir, file, symlink or submodule in the repo @@ -20,8 +20,9 @@ class Gitea::Repository::Entries::UpdateService < Gitea::ClientService # "new_branch": "string" # } # - def initialize(user, repo_name, filepath, body) - @user = user + def initialize(token, owner, repo_name, filepath, body) + @token = token + @owner = owner @repo_name = repo_name @filepath = filepath @body = body @@ -33,11 +34,11 @@ class Gitea::Repository::Entries::UpdateService < Gitea::ClientService private def params - Hash.new.merge(token: user.gitea_token, data: body) + Hash.new.merge(token: token, data: body) end def url - "/repos/#{user.login}/#{repo_name}/contents/#{filepath}".freeze + "/repos/#{owner}/#{repo_name}/contents/#{filepath}".freeze end end diff --git a/app/services/gitea/repository/update_service.rb b/app/services/gitea/repository/update_service.rb index 37903ec9..0d27922b 100644 --- a/app/services/gitea/repository/update_service.rb +++ b/app/services/gitea/repository/update_service.rb @@ -28,6 +28,6 @@ class Gitea::Repository::UpdateService < Gitea::ClientService end def data_params - Hash.new.merge(token: user.gitea_token, data: params) + Hash.new.merge(token: user.gitea_token, data: params).compact end end diff --git a/app/services/gitea/user/register_service.rb b/app/services/gitea/user/register_service.rb index 4b014de6..ec572930 100644 --- a/app/services/gitea/user/register_service.rb +++ b/app/services/gitea/user/register_service.rb @@ -7,8 +7,7 @@ class Gitea::User::RegisterService < Gitea::ClientService end def call - params = {} - params = params.merge(data: user_params) + params = Hash.new.merge(data: user_params, token: @token) post(API_REST, params) end diff --git a/app/services/gitea/user/update_service.rb b/app/services/gitea/user/update_service.rb index ead483a2..5e6108a9 100644 --- a/app/services/gitea/user/update_service.rb +++ b/app/services/gitea/user/update_service.rb @@ -17,7 +17,7 @@ class Gitea::User::UpdateService < Gitea::ClientService # source_id integer($int64) # website string - def initialize(edit_username, params={}, token=nil) + def initialize(edit_username, params={}, token={username: Gitea.gitea_config[:access_key_id], password: Gitea.gitea_config[:access_key_secret]}) @token = token @params = params @edit_username = edit_username diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index f4297acf..dc14d10d 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -12,6 +12,7 @@ class Projects::CreateService < ApplicationService @project = Project.new(project_params) ActiveRecord::Base.transaction do if @project.save! + Project.update_common_projects_count! Repositories::CreateService.new(user, @project, repository_params).call else Rails.logger.info("#############___________create_project_erros______###########{@project.errors.messages}") diff --git a/app/services/projects/migrate_service.rb b/app/services/projects/migrate_service.rb index 2eb9172c..ff0c0643 100644 --- a/app/services/projects/migrate_service.rb +++ b/app/services/projects/migrate_service.rb @@ -9,6 +9,7 @@ class Projects::MigrateService < ApplicationService def call @project = Project.new(project_params) if @project.save! + Project.update_mirror_projects_count! Repositories::MigrateService.new(user, @project, repository_params).call else # diff --git a/app/services/repositories/create_service.rb b/app/services/repositories/create_service.rb index b506d13a..9458e513 100644 --- a/app/services/repositories/create_service.rb +++ b/app/services/repositories/create_service.rb @@ -14,6 +14,18 @@ class Repositories::CreateService < ApplicationService gitea_repository = Gitea::Repository::CreateService.new(user.gitea_token, gitea_repository_params).call sync_project(@repository, gitea_repository) sync_repository(@repository, gitea_repository) + # if project.project_type == "common" + # chain_params = { + # type: "create", + # chain_params:{ + # username: user.try(:login), + # reponame: @repository.try(:identifier), + # token_name: @repository.try(:identifier), + # total_supply: 1000000 + # } + # } + # PostChainJob.perform_later(chain_params) #创建上链操作 + # end else Rails.logger.info("#############___________create_repository_erros______###########{@repository.errors.messages}") end @@ -26,7 +38,7 @@ class Repositories::CreateService < ApplicationService private - def sync_project(repository, gitea_repository) + def sync_project(repository, gitea_repository) if gitea_repository project.update_columns( gpid: gitea_repository["id"], diff --git a/app/tasks/check_gitea_user.rb b/app/tasks/check_gitea_user.rb new file mode 100644 index 00000000..74ab61ff --- /dev/null +++ b/app/tasks/check_gitea_user.rb @@ -0,0 +1,42 @@ +class CheckGiteaUser + # 运行示例: 检查哪些用户的gitea不存在,bundle exec rails runner "CheckGiteaUser.new.call()" + + def call + SyncLog.sync_log("=====begin to check gitea_user======") + + all_users = User.where(type: "User", gitea_token: [nil, ""], gitea_uid: [nil, ""]) + if all_users.present? + new_password = "12345678" + # EMAIL_REGEX = /^[a-zA-Z0-9_\-.]+@[a-zA-Z0-9_\-.]+(\.[a-zA-Z0-9_-]+)+$/i + all_users.each do |user| + begin + SyncLog.sync_log("=====check_user_login_is:#{user.login}======") + + user_mail = user&.mail.present? ? user.mail : "#{user.login}@example.com" + # unless user_mail.match(EMAIL_REGEX).present? + # user_mail = "#{user.login}@example.com" + # end + ActiveRecord::Base.transaction do + interactor = Gitea::RegisterInteractor.call({username: user.login, email: user_mail, password: new_password}) + if interactor.success? + gitea_user = interactor.result + result = Gitea::User::GenerateTokenService.new(user.login, new_password).call + user.gitea_token = result['sha1'] + user.gitea_uid = gitea_user['id'] + if user.save! + SyncLog.sync_log("=================create_gitea_user_success_login==#{user.login}") + else + SyncLog.sync_log("=================create_gitea_user_success_login==#{user.login}") + end + else + SyncLog.sync_log("=============sync_to_user_failed,user_login====#{user.login}") + end + end + rescue => exception + SyncLog.sync_log("=================create_gitea_user_has_erros=#{user.login}===#{exception}") + end + end + end + SyncLog.sync_log("=====end_to_check_gitea_user=====") + end + end \ No newline at end of file diff --git a/app/tasks/check_mirror_rake.rb b/app/tasks/check_mirror_rake.rb new file mode 100644 index 00000000..2afe8e10 --- /dev/null +++ b/app/tasks/check_mirror_rake.rb @@ -0,0 +1,37 @@ +class CheckMirrorRake + # 运行示例: 检查哪些项目的repo不存在,bundle exec rails runner "CheckMirrorRake.new.call()" + + def call + SyncLog.sync_log("=====begin to check mirror======") + empty_repo = [] + empty_user = [] + all_projects = Project.select(:id,:identifier,:user_id, :gpid, :forked_count,:is_public).includes(:owner, :repository) + all_projects.each do |project| + SyncLog.sync_log("=====check_project_id:#{project.id}======") + if project&.owner&.login.present? + response = Gitea::Repository::Branches::ListService.new(project.owner, project.identifier).call + else + response = "224444" + empty_user.push(project.id) + end + unless response.present? + empty_repo.push(project.id) + end + end + + SyncLog.empty_repo_project_log("=====empty_repo_project_ids:#{empty_repo}======") + SyncLog.empty_repo_project_log("=====empty_user_project_ids:#{empty_user}======") + SyncLog.sync_log("=====empty_repo_project_ids:#{empty_repo}======") + SyncLog.sync_log("=====empty_user_project_ids:#{empty_user}======") + + if empty_repo.present? + SyncLog.sync_log("**=====begin_create_empty_repo======**") + empty_repo_projects = all_projects.where(id: empty_repo) + empty_repo_projects.each do |project| + SyncLog.sync_log("**====create_empty_repo_project_id: #{project.id}======**") + CheckMirrorJob.perform_later(project) + end + SyncLog.sync_log("**=====endcreate_empty_repo======**") + end + end + end \ No newline at end of file diff --git a/app/tasks/sync_project_socre_rake.rb b/app/tasks/sync_project_socre_rake.rb new file mode 100644 index 00000000..c8a7348f --- /dev/null +++ b/app/tasks/sync_project_socre_rake.rb @@ -0,0 +1,5 @@ +class SyncProjectScoreRake + # 运行示例: 检查哪些用户的gitea不存在,bundle exec rails runner "SyncProjectScoreRake.new.call()" + + +end \ No newline at end of file diff --git a/app/views/admins/laboratory_settings/_add_tr.html.erb b/app/views/admins/laboratory_settings/_add_tr.html.erb new file mode 100644 index 00000000..2d6ff25d --- /dev/null +++ b/app/views/admins/laboratory_settings/_add_tr.html.erb @@ -0,0 +1,12 @@ + + <%= text_field_tag('navbar[][name]', "", id: nil, class: 'form-control', placeholder: "导航名称") %> + <%= text_field_tag('navbar[][link]', "", id: nil, class: 'form-control', placeholder: "导航链接") %> + + <%= check_box_tag('navbar[][hidden]', 0, false, id: nil, class: 'font-16') %> + + +
+ +
+ + \ No newline at end of file diff --git a/app/views/admins/laboratory_settings/new.js.erb b/app/views/admins/laboratory_settings/new.js.erb new file mode 100644 index 00000000..47eb5aa3 --- /dev/null +++ b/app/views/admins/laboratory_settings/new.js.erb @@ -0,0 +1 @@ +$("#laboratories-show-content").append("<%= j render partial: "admins/laboratory_settings/add_tr" %>") \ No newline at end of file diff --git a/app/views/admins/laboratory_settings/show.html.erb b/app/views/admins/laboratory_settings/show.html.erb index ee9880fb..67536af2 100644 --- a/app/views/admins/laboratory_settings/show.html.erb +++ b/app/views/admins/laboratory_settings/show.html.erb @@ -143,18 +143,23 @@
-
导航设置
+
+
导航设置 + <%= link_to "".html_safe,new_admins_laboratory_laboratory_setting_path, remote: true, class: "btn btn-primary btn-sm"%> +
+
- + - + + - + <% (setting.navbar || setting.default_navbar).each do |nav| %> @@ -162,6 +167,11 @@ + <% end %> @@ -184,4 +194,9 @@ <%= link_to '取消', admins_laboratories_path, class: 'btn btn-secondary px-4' %> <% end %> - \ No newline at end of file + + \ No newline at end of file diff --git a/app/views/admins/projects/shared/_list.html.erb b/app/views/admins/projects/shared/_list.html.erb index d092134c..bd630028 100644 --- a/app/views/admins/projects/shared/_list.html.erb +++ b/app/views/admins/projects/shared/_list.html.erb @@ -28,8 +28,8 @@ - - + +
导航名称导航名称 导航链接是否展示是否展示操作
<%= text_field_tag('navbar[][name]', nav['name'], id: nil, class: 'form-control') %> <%= check_box_tag('navbar[][hidden]', 0, !nav['hidden'], id: nil, class: 'font-16') %> +
+ +
+
<%= project.is_public ? '√' : '' %> <%= project.issues.size %> <%= project.attachments.size %><%= project.project_score.try(:changeset_num).to_i %><%= project.project_score.try(:pull_request_num).to_i %><%= project&.project_score.try(:changeset_num).to_i %><%= project&.project_score.try(:pull_request_num).to_i %> <%= project.versions.size %> <%= project.members.size %> diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index 7287c034..de56a547 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -41,7 +41,7 @@ <% end %>
  • - <%= sidebar_item('/sidekiq', '定时任务', icon: 'bell', controller: 'root') %> + <%= sidebar_item('/admins/sidekiq', '定时任务', icon: 'bell', controller: 'root') %>
  • <%= sidebar_item('/', '返回主站', icon: 'sign-out', controller: 'root') %>
  • diff --git a/app/views/ci/builds/_author.json.jbuilder b/app/views/ci/builds/_author.json.jbuilder new file mode 100644 index 00000000..280f7ef9 --- /dev/null +++ b/app/views/ci/builds/_author.json.jbuilder @@ -0,0 +1,4 @@ +json.id user.id +json.name user.real_name +json.login user.login +json.image_url url_to_avatar(user) diff --git a/app/views/ci/builds/_build.json.jbuilder b/app/views/ci/builds/_build.json.jbuilder new file mode 100644 index 00000000..1c1afcbf --- /dev/null +++ b/app/views/ci/builds/_build.json.jbuilder @@ -0,0 +1,21 @@ +json.id build.build_id +json.repo_id build.build_repo_id +json.number build.build_number +json.status build.build_status +json.event build.build_event +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 +end +json.started format_utc_time build.build_started +json.finished format_utc_time build.build_finished +json.created format_utc_time build.build_created +json.updated format_utc_time build.build_updated +json.version build.build_version +json.build_after_sha build.build_after +json.build_before_sha build.build_before +json.branch_source build.build_source +json.branch_target build.build_target +json.duration_time render_duartion_time(build.build_finished, build.build_started) diff --git a/app/views/ci/builds/_stage.json.jbuilder b/app/views/ci/builds/_stage.json.jbuilder new file mode 100644 index 00000000..95c2eff5 --- /dev/null +++ b/app/views/ci/builds/_stage.json.jbuilder @@ -0,0 +1,23 @@ +json.id stage.stage_id +json.repo_id stage.stage_repo_id +json.build_id stage.stage_build_id +json.name stage.stage_name +json.kind stage.stage_kind +json.type stage.stage_type +json.number stage.stage_number +json.status stage.stage_status +json.errignore stage.stage_errignore +json.exit_code stage.stage_exit_code +json.os stage.stage_os +json.arch stage.stage_arch +json.started format_utc_time(stage.stage_started) +json.stopped format_utc_time(stage.stage_stopped) +json.created format_utc_time(stage.stage_created) +json.updated format_utc_time(stage.stage_updated) +json.duration_time render_duartion_time(stage.stage_stopped, stage.stage_started) +json.version stage.stage_version +json.on_success stage.stage_on_success +json.on_failure stage.stage_on_failure +json.steps stage.steps do |step| + json.partial! "/ci/builds/step", step: step +end diff --git a/app/views/ci/builds/_step.json.jbuilder b/app/views/ci/builds/_step.json.jbuilder new file mode 100644 index 00000000..44d5f366 --- /dev/null +++ b/app/views/ci/builds/_step.json.jbuilder @@ -0,0 +1,9 @@ +json.id step.step_id +json.number step.step_number +json.name step.step_name +json.status step.step_status +json.exit_code step.step_exit_code +json.started format_utc_time(step.step_started) +json.stopped format_utc_time(step.step_stopped) +json.duration_time render_duartion_time(step.step_stopped, step.step_started) +json.version step.step_version diff --git a/app/views/ci/builds/index.json.jbuilder b/app/views/ci/builds/index.json.jbuilder new file mode 100644 index 00000000..a4b24d98 --- /dev/null +++ b/app/views/ci/builds/index.json.jbuilder @@ -0,0 +1,4 @@ +json.total_count @total_count +json.builds @builds do |build| + json.partial! "/ci/builds/build", build: build, user: @user +end diff --git a/app/views/ci/builds/show.json.jbuilder b/app/views/ci/builds/show.json.jbuilder new file mode 100644 index 00000000..0c2b21e2 --- /dev/null +++ b/app/views/ci/builds/show.json.jbuilder @@ -0,0 +1,4 @@ +json.partial! "/ci/builds/build", build: @build +json.stages @build.stages do |stage| + json.partial! "/ci/builds/stage", stage: stage +end diff --git a/app/views/ci/cloud_accounts/bind.json.jbuilder b/app/views/ci/cloud_accounts/bind.json.jbuilder new file mode 100644 index 00000000..cff42cef --- /dev/null +++ b/app/views/ci/cloud_accounts/bind.json.jbuilder @@ -0,0 +1,8 @@ +json.step current_user.devops_step +json.cloud_account do + if @cloud_account && !current_user.devops_uninit? + json.ip @cloud_account.drone_ip + else + json.nil! + end +end diff --git a/app/views/ci/cloud_accounts/oauth_grant.json.jbuilder b/app/views/ci/cloud_accounts/oauth_grant.json.jbuilder new file mode 100644 index 00000000..39d2c064 --- /dev/null +++ b/app/views/ci/cloud_accounts/oauth_grant.json.jbuilder @@ -0,0 +1 @@ +json.step current_user.devops_step diff --git a/app/views/ci/cloud_accounts/show.json.jbuilder b/app/views/ci/cloud_accounts/show.json.jbuilder new file mode 100644 index 00000000..efb2d7db --- /dev/null +++ b/app/views/ci/cloud_accounts/show.json.jbuilder @@ -0,0 +1,9 @@ +json.step current_user.devops_step +json.ci_certification current_user.ci_certification? +json.cloud_account do + if @cloud_account && !current_user.devops_uninit? + json.ip @cloud_account.drone_ip + else + json.nil! + end +end diff --git a/app/views/ci/cloud_accounts/unbind.json.jbuilder b/app/views/ci/cloud_accounts/unbind.json.jbuilder new file mode 100644 index 00000000..e69de29b diff --git a/app/views/ci/languages/common.json.jbuilder b/app/views/ci/languages/common.json.jbuilder new file mode 100644 index 00000000..ba0214c8 --- /dev/null +++ b/app/views/ci/languages/common.json.jbuilder @@ -0,0 +1,6 @@ +json.array! @languages do |lang| + json.id lang.id + json.name lang.name + json.content render_base64_decoded lang.content + json.cover_url lang.cover_id.present? ? download_url(lang.cover) : nil +end diff --git a/app/views/ci/languages/index.json.jbuilder b/app/views/ci/languages/index.json.jbuilder new file mode 100644 index 00000000..ba0214c8 --- /dev/null +++ b/app/views/ci/languages/index.json.jbuilder @@ -0,0 +1,6 @@ +json.array! @languages do |lang| + json.id lang.id + json.name lang.name + json.content render_base64_decoded lang.content + json.cover_url lang.cover_id.present? ? download_url(lang.cover) : nil +end diff --git a/app/views/ci/languages/show.json.jbuilder b/app/views/ci/languages/show.json.jbuilder new file mode 100644 index 00000000..2fbef2ba --- /dev/null +++ b/app/views/ci/languages/show.json.jbuilder @@ -0,0 +1,4 @@ +json.id @language.id +json.name @language.name +json.content render_base64_decoded @language.content +json.cover_url @language.cover_id.present? ? download_url(@language.cover) : nil diff --git a/app/views/ci/projects/authorize.json.jbuilder b/app/views/ci/projects/authorize.json.jbuilder new file mode 100644 index 00000000..d57e07fe --- /dev/null +++ b/app/views/ci/projects/authorize.json.jbuilder @@ -0,0 +1,13 @@ +json.step @user.devops_step +json.ci_certification @user.ci_certification? +json.cloud_account do + if @cloud_account && !@user.devops_uninit? + json.id @cloud_account.id + json.account @cloud_account.account + json.ip @cloud_account.drone_ip + json.secret @cloud_account.visible_secret + json.authenticate_url @cloud_account.authenticate_url if @user.devops_unverified? + else + json.nil! + end +end diff --git a/app/views/compare/index.json.jbuilder b/app/views/compare/index.json.jbuilder new file mode 100644 index 00000000..e69de29b diff --git a/app/views/compare/show.json.jbuilder b/app/views/compare/show.json.jbuilder new file mode 100644 index 00000000..8f95bbcb --- /dev/null +++ b/app/views/compare/show.json.jbuilder @@ -0,0 +1,13 @@ +json.commits_count @compare_result['Commits']&.size +json.commits @compare_result['Commits'], partial: 'pull_requests/commit', as: :commit + +json.diff do + if @compare_result['Diff'].blank? + json.nil! + else + 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']} + end +end diff --git a/app/views/issues/edit.json.jbuilder b/app/views/issues/edit.json.jbuilder index 382dab1b..eae63c3c 100644 --- a/app/views/issues/edit.json.jbuilder +++ b/app/views/issues/edit.json.jbuilder @@ -3,6 +3,8 @@ json.extract! @issue, :id,:subject,:description,:is_private,:assigned_to_id,:tra :start_date,:due_date,:estimated_hours, :issue_type, :token,:issue_classify, :branch_name json.done_ratio @issue.done_ratio.to_s + "%" json.issue_tags @issue.get_issue_tags +json.cannot_edit_tags @cannot_edit_tags +json.issue_current_user @issue.author_id == current_user.try(:id) # json.issue_chosen @issue_chosen # json.branches @all_branches json.attachments do diff --git a/app/views/issues/new.json.jbuilder b/app/views/issues/new.json.jbuilder index f47ce3e7..03c7608a 100644 --- a/app/views/issues/new.json.jbuilder +++ b/app/views/issues/new.json.jbuilder @@ -1,3 +1,2 @@ json.partial! "commons/success" -json.branches @all_branches -json.issue_chosen @issue_chosen \ No newline at end of file +json.issue_chosen @issue_chosen diff --git a/app/views/issues/show.json.jbuilder b/app/views/issues/show.json.jbuilder index 156031f7..be6de14e 100644 --- a/app/views/issues/show.json.jbuilder +++ b/app/views/issues/show.json.jbuilder @@ -1,5 +1,5 @@ json.partial! "commons/success" -json.extract! @issue, :id,:subject,:is_lock,:description,:is_private, :start_date,:due_date,:estimated_hours +json.extract! @issue, :id,:subject,:is_lock,:description,:is_private, :start_date,:due_date,:estimated_hours, :status_id json.user_permission @user_permission json.closed_on @issue.closed_on.present? ? format_time(@issue.closed_on) : "" diff --git a/app/views/layouts/oauth_register.html.erb b/app/views/layouts/oauth_register.html.erb new file mode 100644 index 00000000..1e43ddbe --- /dev/null +++ b/app/views/layouts/oauth_register.html.erb @@ -0,0 +1,14 @@ + + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + <%= javascript_include_tag '/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3', '': '' %> + <%= stylesheet_link_tag '/stylesheets/css/oauth', '', :media => 'all' %> + + +
    + <%= image_tag('/images/oauth/logo.png') %> + <%= yield %> +
    + + diff --git a/app/views/members/_member.json.jbuilder b/app/views/members/_member.json.jbuilder index 5a3d3dc0..45a0837e 100644 --- a/app/views/members/_member.json.jbuilder +++ b/app/views/members/_member.json.jbuilder @@ -3,3 +3,4 @@ json.name user.real_name json.login user.login json.image_url url_to_avatar(user) json.email user.try(:mail) +# json.token get_user_token(user.try(:login),@project.try(:identifier)) diff --git a/app/views/oauth/register.html.erb b/app/views/oauth/register.html.erb new file mode 100644 index 00000000..96778fa0 --- /dev/null +++ b/app/views/oauth/register.html.erb @@ -0,0 +1,78 @@ +
    +

    完善信息,进入比赛

    +
    + + <%= form_tag('', method: :post, id: 'oauth_form', class: 'form-inline search-form flex-1', remote: true) do %> + <%= hidden_field_tag 'callback_url', params[:callback_url] %> +
    + 用户名: + <%= text_field_tag :login, params[:login], placeholder: '请输入用户名', readonly: true, id: 'login' %> +

    +
    +
    + 邮箱: + <%= text_field_tag :mail, params[:mail], placeholder: '请输入绑定邮箱', maxlength: 40, id: 'email' %> +

    +
    +
    + 密码: + <%= password_field_tag :password, '', placeholder: '请输入账号密码', id: 'password' %> +

    +
    +
    + +
    + <% end %> +
    +
    + diff --git a/app/views/project_categories/group_list.json.jbuilder b/app/views/project_categories/group_list.json.jbuilder index 07ce8834..f13d6ecf 100644 --- a/app/views/project_categories/group_list.json.jbuilder +++ b/app/views/project_categories/group_list.json.jbuilder @@ -1,5 +1,5 @@ -json.array! @category_group_list do |category,v| - json.id category[0] - json.name category[1] - json.projects_count v -end \ No newline at end of file +json.array! @project_categories do |category| + json.id category.id + json.name category.name + json.projects_count category.projects_count +end diff --git a/app/views/projects/_project_detail.json.jbuilder b/app/views/projects/_project_detail.json.jbuilder index d7cd196e..fdbd05df 100644 --- a/app/views/projects/_project_detail.json.jbuilder +++ b/app/views/projects/_project_detail.json.jbuilder @@ -1,10 +1,6 @@ -user = project.owner -if user.blank? - nil -else - json.id project.id +json.id project.id json.repo_id project&.repository&.id -json.identifier project.identifier +json.identifier render_identifier(project) json.name project.name json.description Nokogiri::HTML(project.description).text json.visits project.visits @@ -16,11 +12,22 @@ json.type project&.numerical_for_project_type json.last_update_time render_unix_time(project.updated_on) json.time_ago time_from_now(project.updated_on) json.forked_from_project_id project.forked_from_project_id +json.open_devops project.open_devops? +json.platform project.platform json.author do - json.name user.try(:show_real_name) - json.login user.login - json.image_url url_to_avatar(project.owner) + if project.educoder? + project_educoder = project.project_educoder + json.name project_educoder&.owner + json.login project_educoder&.repo_name.split('/')[0] + json.image_url render_educoder_avatar_url(project.project_educoder) + else + user = project.owner + json.name user.try(:show_real_name) + json.login user.login + json.image_url render_avatar_url(user) + end end + json.category do if project.project_category.blank? json.nil! @@ -37,4 +44,3 @@ json.language do json.name project.project_language.name end end -end diff --git a/app/views/projects/about.json.jbuilder b/app/views/projects/about.json.jbuilder new file mode 100644 index 00000000..72041ca6 --- /dev/null +++ b/app/views/projects/about.json.jbuilder @@ -0,0 +1,5 @@ +json.content @project_detail&.content +json.identifier @project.identifier +json.attachments @attachments do |attach| + json.partial! "attachments/attachment_simple", locals: {attachment: attach} +end diff --git a/app/views/projects/ci_authorize.json.jbuilder b/app/views/projects/ci_authorize.json.jbuilder new file mode 100644 index 00000000..8882d26a --- /dev/null +++ b/app/views/projects/ci_authorize.json.jbuilder @@ -0,0 +1,11 @@ +json.step @user.devops_step +json.cloud_account do + if @cloud_account && !@user.devops_uninit? + json.account @cloud_account.account + json.ip @cloud_account.drone_ip + json.secret @cloud_account.visible_secret + json.redirect_url "#{@cloud_account.drone_url}/login" if @user.devops_unverified? + else + json.nil! + end +end diff --git a/app/views/projects/fork_users.json.jbuilder b/app/views/projects/fork_users.json.jbuilder index 95e69ca7..a539797e 100644 --- a/app/views/projects/fork_users.json.jbuilder +++ b/app/views/projects/fork_users.json.jbuilder @@ -1,12 +1,12 @@ json.count @forks_count -json.users do +json.users do json.array! @fork_users.each do |f| - user = f.user - fork_project = Project.select(:id,:name).find_by(id: f.fork_project_id) - json.id f.fork_project_id - json.name "#{user.try(:show_real_name)}/#{fork_project.try(:name)}" + user = f.user + json.id f.fork_project.id + json.identifier f.fork_project.identifier + json.name "#{user.try(:show_real_name)}/#{f.fork_project.try(:name)}" json.login user.try(:login) json.image_url url_to_avatar(user) json.format_time f.created_at.strftime("%Y-%m-%d") end -end \ No newline at end of file +end diff --git a/app/views/projects/group_type_list.json.jbuilder b/app/views/projects/group_type_list.json.jbuilder index 34d46894..542c3eff 100644 --- a/app/views/projects/group_type_list.json.jbuilder +++ b/app/views/projects/group_type_list.json.jbuilder @@ -1,5 +1,5 @@ -json.array! @project_group_list do |type,v| - json.project_type type - json.name render_zh_project_type(type) - json.projects_count v -end \ No newline at end of file +json.array! @project_statics_list do |static| + json.project_type static[:project_type] + json.name static[:name] + json.projects_count static[:projects_count] +end diff --git a/app/views/projects/index.json.jbuilder b/app/views/projects/index.json.jbuilder index 28b7df1b..5556cfe2 100644 --- a/app/views/projects/index.json.jbuilder +++ b/app/views/projects/index.json.jbuilder @@ -1,4 +1,50 @@ json.total_count @total_count json.projects @projects do |project| - json.partial! "/projects/project_detail", project: project + # json.partial! "/projects/project_detail", project: project + json.id project.id + json.repo_id project&.repository&.id + json.identifier render_identifier(project) + json.name project.name + json.description Nokogiri::HTML(project.description).text + json.visits project.visits + json.praises_count project.praises_count.to_i + json.forked_count project.forked_count.to_i + json.is_public project.is_public + json.mirror_url project.repository&.mirror_url + json.type project&.numerical_for_project_type + json.last_update_time render_unix_time(project.updated_on) + json.time_ago time_from_now(project.updated_on) + json.forked_from_project_id project.forked_from_project_id + json.open_devops project.open_devops? + json.platform project.platform + json.author do + if project.educoder? + project_educoder = project.project_educoder + json.name project_educoder&.owner + json.login project_educoder&.repo_name.split('/')[0] + json.image_url render_educoder_avatar_url(project.project_educoder) + else + user = project.owner + json.name user.try(:show_real_name) + json.login user.login + json.image_url render_avatar_url(user) + end + end + + json.category do + if project.project_category.blank? + json.nil! + else + json.id project.project_category.id + json.name project.project_category.name + end + end + json.language do + if project.project_language.blank? + json.nil! + else + json.id project.project_language.id + json.name project.project_language.name + end + end end diff --git a/app/views/projects/migrate.json.jbuilder b/app/views/projects/migrate.json.jbuilder index 818eb018..c9ae044e 100644 --- a/app/views/projects/migrate.json.jbuilder +++ b/app/views/projects/migrate.json.jbuilder @@ -1 +1 @@ -json.extract! @project, :id, :name +json.extract! @project, :id, :name, :identifier diff --git a/app/views/projects/recommend.json.jbuilder b/app/views/projects/recommend.json.jbuilder new file mode 100644 index 00000000..1da5be40 --- /dev/null +++ b/app/views/projects/recommend.json.jbuilder @@ -0,0 +1,22 @@ +json.array! @projects do |project| + owner = project.owner + json.id project.id + json.repo_id project&.repository&.id + json.identifier project.identifier + json.name project.name + json.visits project.visits + json.author do + json.name owner.try(:show_real_name) + json.login owner.login + json.image_url url_to_avatar(owner) + end + + json.category do + if project.project_category.blank? + json.nil! + else + json.id project.project_category.id + json.name project.project_category.name + end + end +end diff --git a/app/views/pull_requests/_commit.json.jbuilder b/app/views/pull_requests/_commit.json.jbuilder new file mode 100644 index 00000000..0b7db589 --- /dev/null +++ b/app/views/pull_requests/_commit.json.jbuilder @@ -0,0 +1,14 @@ +json.author do + author = User.find_by(login: commit['Author']['Name']) + json.partial! 'repositories/commit_author', locals: { user: author } +end + +json.committer do + author = User.find_by(login: commit['Committer']['Name']) + json.partial! 'repositories/commit_author', locals: { user: author } +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'] diff --git a/app/views/pull_requests/_diff_file.json.jbuilder b/app/views/pull_requests/_diff_file.json.jbuilder new file mode 100644 index 00000000..faec9065 --- /dev/null +++ b/app/views/pull_requests/_diff_file.json.jbuilder @@ -0,0 +1,41 @@ +json.sha sha +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 diff --git a/app/views/pull_requests/commits.json.jbuilder b/app/views/pull_requests/commits.json.jbuilder new file mode 100644 index 00000000..57ffa726 --- /dev/null +++ b/app/views/pull_requests/commits.json.jbuilder @@ -0,0 +1,2 @@ +json.commits_count @commits_result.size +json.commits @commits_result, partial: 'commit', as: :commit diff --git a/app/views/pull_requests/edit.json.jbuilder b/app/views/pull_requests/edit.json.jbuilder index 2e91aa53..c6f41559 100644 --- a/app/views/pull_requests/edit.json.jbuilder +++ b/app/views/pull_requests/edit.json.jbuilder @@ -9,3 +9,6 @@ json.project_login @project.owner.try(:login) json.extract! @pull_request, :id, :title, :body, :milestone,:head,:base,:is_original json.extract! @issue, :assigned_to_id, :fixed_version_id, :priority_id json.issue_tag_ids @issue&.issue_tags_value&.split(",") +json.commits_count @pull_request.commits_count +json.files_count @pull_request.files_count +json.comments_count @pull_request.comments_count diff --git a/app/views/pull_requests/files.json.jbuilder b/app/views/pull_requests/files.json.jbuilder new file mode 100644 index 00000000..b40fe606 --- /dev/null +++ b/app/views/pull_requests/files.json.jbuilder @@ -0,0 +1,4 @@ +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']} diff --git a/app/views/pull_requests/index.json.jbuilder b/app/views/pull_requests/index.json.jbuilder index c36bfe1d..14454d70 100644 --- a/app/views/pull_requests/index.json.jbuilder +++ b/app/views/pull_requests/index.json.jbuilder @@ -19,6 +19,7 @@ json.issues do json.pull_request_staus pr.status == 1 ? "merged" : (pr.status == 2 ? "closed" : "open") json.is_original pr.is_original json.fork_project_id pr&.fork_project_id + json.fork_project_identifier pr&.fork_project&.identifier json.fork_project_user pr&.fork_project&.owner.try(:login) diff --git a/app/views/pull_requests/new.json.jbuilder b/app/views/pull_requests/new.json.jbuilder index ab0e8713..8110e297 100644 --- a/app/views/pull_requests/new.json.jbuilder +++ b/app/views/pull_requests/new.json.jbuilder @@ -1,5 +1,6 @@ json.partial! "commons/success" -json.project_id @project.id +json.project_id @project.identifier +json.id @project.id json.branches @all_branches json.is_fork @is_fork json.projects_names @projects_names diff --git a/app/views/pull_requests/show.json.jbuilder b/app/views/pull_requests/show.json.jbuilder index b525d543..61bbc915 100644 --- a/app/views/pull_requests/show.json.jbuilder +++ b/app/views/pull_requests/show.json.jbuilder @@ -1,6 +1,9 @@ json.partial! "commons/success" json.project_name @project.name json.pr_time time_from_now(@pull_request.updated_at) +json.commits_count @pull_request.commits_count +json.files_count @pull_request.files_count +json.comments_count @pull_request.comments_count json.pull_request do json.extract! @pull_request, :id,:base, :head, :status,:fork_project_id, :is_original @@ -24,8 +27,3 @@ json.issue do json.version @issue.version.try(:name) json.issue_tags @issue.get_issue_tags end - - - - - diff --git a/app/views/repositories/_author.json.jbuilder b/app/views/repositories/_author.json.jbuilder index 0c2a177c..32692022 100644 --- a/app/views/repositories/_author.json.jbuilder +++ b/app/views/repositories/_author.json.jbuilder @@ -1,5 +1,11 @@ json.author do - json.login user.login - json.name user.real_name - json.image_url url_to_avatar(user) + if @project.forge? + json.login user.login + json.name user.real_name + json.image_url url_to_avatar(user) + else + json.login @project.project_educoder&.repo_name&.split('/')[0] + json.name @project.project_educoder&.owner + json.image_url @project.project_educoder&.image_url + end end diff --git a/app/views/repositories/_commit.json.jbuilder b/app/views/repositories/_commit.json.jbuilder index 5ad8a1bc..079473b3 100644 --- a/app/views/repositories/_commit.json.jbuilder +++ b/app/views/repositories/_commit.json.jbuilder @@ -1,16 +1,34 @@ -json.commit do - json.sha commit['sha'] - json.url EduSetting.get('host_name') + commit_repository_path(project.repository, commit['sha']) - json.message commit['commit']['message'] - json.author commit['commit']['author'] - json.committer commit['commit']['committer'] - json.timestamp render_unix_time(commit['commit']['committer']['date']) - json.time_from_now time_from_now(commit['commit']['committer']['date']) +if @project.educoder? + json.commit do + json.sha commit[0]['id'] + json.message commit[0]['title'] + json.author {} + json.committer {} + json.timestamp 0 + json.time_from_now commit[0]['time'] + end + json.author do + {} + # json.partial! '/projects/author', user: render_commit_author(commit['author']) + end + json.committer {} end -json.author do - json.partial! 'commit_author', user: render_commit_author(commit['author']) -end -json.committer do - json.partial! 'commit_author', user: render_commit_author(commit['committer']) +if @project.forge? + json.commit do + json.sha commit['sha'] + # json.url EduSetting.get('host_name') + commit_repository_path(project.repository, commit['sha']) + json.message commit['commit']['message'] + json.author commit['commit']['author'] + json.committer commit['commit']['committer'] + json.timestamp render_unix_time(commit['commit']['committer']['date']) + json.time_from_now time_from_now(commit['commit']['committer']['date']) + end + + json.author do + json.partial! 'commit_author', user: render_commit_author(commit['author']) + end + json.committer do + json.partial! 'commit_author', user: render_commit_author(commit['committer']) + end end diff --git a/app/views/repositories/_last_commit.json.jbuilder b/app/views/repositories/_last_commit.json.jbuilder index 9d6bbe34..3c218463 100644 --- a/app/views/repositories/_last_commit.json.jbuilder +++ b/app/views/repositories/_last_commit.json.jbuilder @@ -1,8 +1,7 @@ -created_at = Time.at(entry['latest_commit']['created_at'].to_i).strftime("%Y-%m-%d %H:%M") json.commit do json.message entry['latest_commit']['message'] json.sha entry['latest_commit']['sha'] - json.created_at created_at - json.time_from_now time_from_now(created_at) + json.created_at render_format_time_with_unix(entry['latest_commit']['created_at'].to_i) + json.time_from_now time_from_now(render_format_time_with_unix(entry['latest_commit']['created_at'].to_i)) json.created_at_unix entry['latest_commit']['created_at'] end diff --git a/app/views/repositories/_simple_entry.json.jbuilder b/app/views/repositories/_simple_entry.json.jbuilder index 4890f404..ab9910dd 100644 --- a/app/views/repositories/_simple_entry.json.jbuilder +++ b/app/views/repositories/_simple_entry.json.jbuilder @@ -1,18 +1,44 @@ -file_name = entry['name'] -file_type = file_name.to_s.split(".").last -direct_download = download_type(file_type) -image_type = image_type?(file_type) -json.name file_name -json.sha entry['sha'] -json.path entry['path'] -json.type entry['type'] -json.size entry['size'] -json.content entry['content'].present? && !direct_download ? render_decode64_content(entry['content']).force_encoding('UTF-8') : "" -json.target entry['target'] -json.download_url entry['download_url'] -json.direct_download direct_download -json.image_type image_type -json.is_readme_file is_readme_type?(file_name) -if entry['latest_commit'] - json.partial! 'last_commit', entry: entry +if @project.forge? + file_name = entry['name'] + file_type = file_name.to_s.split(".").last + direct_download = download_type(file_type) + image_type = image_type?(file_type) + json.name file_name + json.sha entry['sha'] + json.path entry['path'] + json.type entry['type'] + json.size entry['size'] + json.content entry['content'].present? && !direct_download ? render_decode64_content(entry['content']) : "" + json.target entry['target'] + json.download_url entry['download_url'] + json.direct_download direct_download + json.image_type image_type + json.is_readme_file is_readme_type?(file_name) + if entry['latest_commit'] + if entry['type'] != 'file' + json.partial! 'last_commit', entry: entry + else + json.commit nil + end + end +end + +if @project.educoder? + file_path = params[:filepath].present? ? [params[:filepath], entry['name']].join('/') : entry['name'] + + json.name entry['name'] + json.sha nil + json.path file_path + json.type entry['type'] === 'blob'? 'file' : 'dir' + json.size 0 + json.content entry['content'] + json.target nil + json.download_url nil + json.direct_download false + json.image_type false + json.is_readme_file false + if entry['latest_commit'] + # json.partial! 'last_commit', entry: entry + json.partial! 'repositories/simple_entry', locals: { entry: entry } + end end diff --git a/app/views/repositories/commit.json.jbuilder b/app/views/repositories/commit.json.jbuilder index 8901cad3..77f6e3f1 100644 --- a/app/views/repositories/commit.json.jbuilder +++ b/app/views/repositories/commit.json.jbuilder @@ -1,27 +1,11 @@ -json.key_format! camelize: :lower -json.additions @commit['commit_diff']['TotalAddition'] -json.deletions @commit['commit_diff']['TotalDeletion'] -json.sha @commit['sha'] -json.url request.url -json.commit do - @commit['commit'].delete('url') - json.author @commit['commit']['author'] - json.committer @commit['commit']['committer'] - json.message @commit['commit']['message'] - json.tree do - @commit['commit']['tree']['sha'] - end -end -json.author do - json.partial! 'commit_author', user: render_commit_author(@commit['author']) -end -json.committer do - json.partial! 'commit_author', user: render_commit_author(@commit['committer']) -end +# json.key_format! camelize: :lower +json.files_count @commit_diff['NumFiles'] +json.total_addition @commit_diff['TotalAddition'] +json.total_deletion @commit_diff['TotalDeletion'] +json.files @commit_diff['Files'], partial: 'pull_requests/diff_file', as: :file, locals: {sha: @sha} +json.partial! 'commit', commit: @commit, project: @project json.parents @commit['parents'] do |parent| json.sha parent['sha'] - json.url EduSetting.get('host_name') + commit_repository_path(@repo, parent['sha']) + # json.url EduSetting.get('host_name') + commit_repository_path(@repo, parent['sha']) end - -json.files @commit['commit_diff']['Files'] diff --git a/app/views/repositories/entries.json.jbuilder b/app/views/repositories/entries.json.jbuilder index 636845ef..20fecec3 100644 --- a/app/views/repositories/entries.json.jbuilder +++ b/app/views/repositories/entries.json.jbuilder @@ -1,36 +1,71 @@ -json.last_commit do - if @latest_commit - json.partial! 'commit', commit: @latest_commit, project: @project - else - json.nil! +if @project.educoder? + json.last_commit do + if @entries['commits'] + json.partial! 'commit', commit: @entries['commits'], project: @project + else + json.nil! + end end -end -#json.tags_count @tags_count -#json.branches_count @branches_count -#json.commits_count @commits_count -json.zip_url render_zip_url(@project, @ref) -json.tar_url render_tar_url(@project, @ref) -json.entries do - json.array! @entries do |entry| - json.name entry['name'] - json.path entry['path'] - json.sha entry['sha'] - json.type entry['type'] - json.size entry['size'] - content = - if is_readme_type?(entry['name']) - is_readme_file = true - content = Gitea::Repository::Entries::GetService.call(@project_owner, @project.identifier, entry['name'], ref: @ref)['content'] - readme_render_decode64_content(content, @path) - else - is_readme_file = false - entry['content'] + json.commits_count @entries['commit_count'] + json.zip_url @entries['git_url'] + json.tar_url '' + json.entries do + json.array! @entries['trees'] do |entry| + json.name entry['name'] + json.path entry['name'] + json.sha nil + json.type entry['type'] === 'blob'? 'file' : 'dir' + json.size 0 + json.is_readme_file false + json.content nil + json.target nil + json.commit do + json.message entry['title'] + json.time_from_now entry['time'] + json.sha nil + json.created_at_unix nil + json.created_at nil + end + end + end +end + + +if @project.forge? + json.last_commit do + if @latest_commit + json.partial! 'commit', commit: @latest_commit, project: @project + else + json.nil! + end + end + #json.tags_count @tags_count + #json.branches_count @branches_count + #json.commits_count @commits_count + json.zip_url render_zip_url(@project, @ref) + json.tar_url render_tar_url(@project, @ref) + json.entries do + json.array! @entries do |entry| + json.name entry['name'] + json.path entry['path'] + json.sha entry['sha'] + json.type entry['type'] + json.size entry['size'] + content = + if is_readme_type?(entry['name']) + is_readme_file = true + content = Gitea::Repository::Entries::GetService.call(@owner, @project.identifier, entry['name'], ref: @ref)['content'] + readme_render_decode64_content(content, @path) + else + is_readme_file = false + entry['content'] + end + json.is_readme_file is_readme_file + json.content content + json.target entry['target'] + if entry['latest_commit'] + json.partial! 'last_commit', entry: entry end - json.is_readme_file is_readme_file - json.content content - json.target entry['target'] - if entry['latest_commit'] - json.partial! 'last_commit', entry: entry end end end diff --git a/app/views/repositories/show.json.jbuilder b/app/views/repositories/show.json.jbuilder index eecd3752..80e833ed 100644 --- a/app/views/repositories/show.json.jbuilder +++ b/app/views/repositories/show.json.jbuilder @@ -1,10 +1,10 @@ -json.identifier @project.identifier +json.identifier render_identifier(@project) json.name @project.name json.project_id @project.id json.repo_id @repo.id json.issues_count @project.issues_count.to_i - @project.pull_requests_count.to_i json.pull_requests_count @project.pull_requests_count -json.project_identifier @project.identifier +json.project_identifier render_identifier(@project) json.praises_count @project.praises_count.to_i json.forked_count @project.forked_count.to_i json.watchers_count @project.watchers_count.to_i @@ -12,10 +12,11 @@ json.versions_count @project.versions_count #里程碑数量 json.version_releases_count @project.releases_size(@user.try(:id), "all") json.version_releasesed_count @project.releases_size(@user.try(:id), "released") #已发行的版本 json.contributor_users_count @project.contributor_users -json.permission @project.get_premission(@user) +json.permission render_permission(@user, @project) json.mirror_url @project&.repository.mirror_url json.mirror @project&.repository.mirror_url.present? json.type @project.numerical_for_project_type +json.open_devops @project.open_devops? unless @project.common? json.mirror_status @repo.mirror_status @@ -31,6 +32,7 @@ json.fork_info do if @fork_project.present? json.fork_form_name @fork_project.try(:name) json.fork_project_user_login @fork_project_user.try(:login) + json.fork_project_identifier @fork_project.identifier json.fork_project_user_name @fork_project_user.try(:show_real_name) end end diff --git a/app/views/repositories/sub_entries.json.jbuilder b/app/views/repositories/sub_entries.json.jbuilder index 2032df85..3276ed0d 100644 --- a/app/views/repositories/sub_entries.json.jbuilder +++ b/app/views/repositories/sub_entries.json.jbuilder @@ -1,16 +1,31 @@ +if @project.forge? + json.last_commit do + if @latest_commit + json.partial! 'commit', commit: @latest_commit, project: @project + else + json.nil! + end + end + json.entries do + if @sub_entries.is_a?(Array) + json.partial! 'repositories/simple_entry', collection: @sub_entries, as: :entry + elsif @sub_entries.is_a?(Hash) + json.partial! 'repositories/simple_entry', locals: { entry: @sub_entries } + end + end +end -json.last_commit do - if @latest_commit - json.partial! 'commit', commit: @latest_commit, project: @project - else - json.nil! - end -end -#json.tags_count @tags_count -#json.branches_count @branches_count -#json.commits_count @commits_count -json.entries do - json.array! @sub_entries do |entry| - json.partial! 'repositories/simple_entry', locals: { entry: entry } +if @project.educoder? + json.last_commit do + if @sub_entries['commits'] + json.partial! 'commit', commit: @sub_entries['commits'], project: @project + else + json.nil! + end + end + json.entries do + json.array! @sub_entries['trees'] do |entry| + json.partial! 'repositories/simple_entry', locals: { entry: entry } + end end end diff --git a/app/views/settings/show.json.jbuilder b/app/views/settings/show.json.jbuilder index eac6b8eb..7de12345 100644 --- a/app/views/settings/show.json.jbuilder +++ b/app/views/settings/show.json.jbuilder @@ -16,7 +16,16 @@ json.setting do # # json.footer setting.footer || default_setting.footer # - # json.main_site current_laboratory.main_site? + # end + + nav_bar = default_setting.navbar + + # if User.current.logged? + # nav_bar[2]["link"] = "https://forgeplus.trustie.net/users/#{current_user.login}/projects" + # nav_bar[2]["hidden"] = false + # else + # nav_bar[2]["link"] = "" + # nav_bar[2]["hidden"] = true # end json.name default_setting.name @@ -30,7 +39,7 @@ json.setting do json.moop_cases_banner_url default_setting.moop_cases_banner_url&.[](1..-1) json.oj_banner_url default_setting.oj_banner_url&.[](1..-1) - json.navbar default_setting.navbar + json.navbar nav_bar json.footer default_setting.footer @@ -39,4 +48,4 @@ json.setting do json.old_projects_url @old_projects_url -end \ No newline at end of file +end diff --git a/app/views/users/devops.json.jbuilder b/app/views/users/devops.json.jbuilder new file mode 100644 index 00000000..5830720e --- /dev/null +++ b/app/views/users/devops.json.jbuilder @@ -0,0 +1,11 @@ +json.step @user.devops_step +json.cloud_account do + if @cloud_account && !@user.devops_uninit? + json.account @cloud_account.account + json.ip @cloud_account.drone_ip + json.secret @cloud_account.visible_secret + json.authenticate_url @cloud_account.authenticate_url if @user.devops_unverified? + else + json.nil! + end +end diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index 1096abf4..61b15543 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -13,5 +13,5 @@ json.user_phone_binded @user.phone.present? json.profile_completed @user.profile_completed? json.professional_certification @user.professional_certification json.description @user.description - - +json.devops_step @user.devops_step +json.ci_certification @user.ci_certification? diff --git a/app/views/users/projects.json.jbuilder b/app/views/users/projects.json.jbuilder index 822402a2..d00ec68b 100644 --- a/app/views/users/projects.json.jbuilder +++ b/app/views/users/projects.json.jbuilder @@ -1,6 +1,4 @@ json.count @total_count json.projects do - json.array! @projects do |project| - json.partial! "/projects/project_detail", project: project - end + json.partial! '/projects/project_detail', collection: @projects, as: :project end diff --git a/config/database.yml.example b/config/database.yml.example index 42dc3df2..26e752e4 100644 --- a/config/database.yml.example +++ b/config/database.yml.example @@ -19,6 +19,7 @@ default: &default development: <<: *default + host: 127.0.0.1 database: forge_development # Warning: The database defined as "test" will be erased and diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index ef056bbe..60855f79 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -12,5 +12,4 @@ Rails.application.config.assets.paths << Rails.root.join('vendor/assets') # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in the app/assets # folder are already added. -Rails.application.config.assets.precompile += %w( admin.js admin.css college.js college.css cooperative.js cooperative.css ) - +Rails.application.config.assets.precompile += %w( admin.js admin.css college.js college.css cooperative.js cooperative.css oauth.css ) diff --git a/config/routes.rb b/config/routes.rb index a87cfe45..0bd2b241 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,18 +3,26 @@ Rails.application.routes.draw do require 'sidekiq/web' require 'admin_constraint' - mount Sidekiq::Web => '/sidekiq', :constraints => AdminConstraint.new + # mount Sidekiq::Web => '/sidekiq', :constraints => AdminConstraint.new # Serve websocket cable requests in-process mount ActionCable.server => '/cable' + get 'attachments/entries/get_file', to: 'attachments#get_file' get 'attachments/download/:id', to: 'attachments#show' get 'attachments/download/:id/:filename', to: 'attachments#show' + get 'auth/qq/callback', to: 'oauth/qq#create' get 'auth/failure', to: 'oauth/base#auth_failure' get 'auth/cas/callback', to: 'oauth/cas#create' + + get 'oauth/bind', to: 'oauth/educoder#bind' + get 'oauth/register', to: 'oauth#register' + post 'oauth/auto_register', to: 'oauth#auto_register' + resources :edu_settings + resources :edu_settings scope '/api' do get 'wallets/balance' get 'wallets/coin_changes' @@ -34,15 +42,37 @@ Rails.application.routes.draw do end end - resources :sync_forge, only: [:create] do - collection do + namespace :ci do + resources :languages, only: [:index, :show] do + collection do + get :common + end + end + + # resources :repos, only: :index do + # collection do + # get 'get_trustie_pipeline', to: 'builds#get_trustie_pipeline', as: 'get_trustie_pipeline' + # get ':number', to: 'builds#detail', as: 'detail' + # post ':number', to: 'builds#restart', as: 'restart' + # delete ':number', to: 'builds#delete', as: 'delete' + # get ':number/logs/:stage/:step', to: 'builds#logs', as: 'logs' + # end + # end + end + + resources :sync_forge, only: [:create] do + collection do post :sync_users + post :sync_range_projects end end resources :composes do resources :compose_projects, only: [:create, :destroy] end resources :attachments do + member do + post :preview_attachment + end collection do delete :destroy_files end @@ -85,41 +115,6 @@ Rails.application.routes.draw do end end resources :projects do - resources :hooks - resources :pull_requests, except: [:destroy] do - member do - post :pr_merge - # post :check_merge - post :refuse_merge - end - collection do - post :check_can_merge - get :create_merge_infos - get :get_branches - end - end - resources :version_releases, only: [:index,:new, :create, :edit, :update, :destroy] - resources :project_trends, only: [:index, :create] - resources :issues do - collection do - get :commit_issues - get :index_chosen - post :clean - post :series_update - end - member do - post :copy - post :close_issue - post :lock_issue - end - end - resources :issue_tags, only: [:create, :edit, :update, :destroy, :index] - resources :versions do - member do - post :update_status - end - end - resources :praise_tread, only: [:index] do collection do post :like @@ -127,25 +122,11 @@ Rails.application.routes.draw do get :check_like end end - resources :members, only: [:index, :create] do - collection do - delete :remove - put :change_role - end - end - resources :forks, only: [:create] + collection do post :migrate get :group_type_list - post :watch - end - member do - get :branches - post :watch - get :watch_users - get :praise_users - get :fork_users - get :simple + get :recommend end end @@ -191,11 +172,38 @@ Rails.application.routes.draw do post :sync_salt get :trustie_projects get :trustie_related_projects + + scope '/ci', module: :ci do + scope do + post( + '/cloud_account/bind', + to: 'cloud_accounts#bind', + as: :bind_cloud_acclount + ) + + get( + '/cloud_account', + to: 'cloud_accounts#show', + as: :get_cloud_account + ) + + delete( + '/cloud_account/unbind', + to: 'cloud_accounts#unbind', + as: :unbind_cloud_acclount + ) + + get( + 'oauth_grant', + to: 'cloud_accounts#oauth_grant', + as: :ci_oauth_grant + ) + end + end end scope module: :users do - # resources :courses, only: [:index] - resources :projects, only: [:index] + # resources :projects, only: [:index] # resources :subjects, only: [:index] resources :project_packages, only: [:index] # 私信 @@ -205,11 +213,6 @@ Rails.application.routes.draw do # resource :unread_message_info, only: [:show] end - - resources :projects, module: :users, only: [] do - get :search, on: :collection - end - resources :tidings, only: [:index] scope module: :users do @@ -228,23 +231,6 @@ Rails.application.routes.draw do end end - resources :repositories, only: [:index, :show, :edit] do - member do - get :entries - match :sub_entries, via: [:get, :put] - get :commits - post :files - get :tags - post :create_file - put :update_file - delete :delete_file - post :repo_hook - post :sync_mirror - get :top_counts - get 'commits/:sha', to: 'repositories#commit', as: 'commit' - end - end - resources :users_for_private_messages, only: [:index] resources :files, only: [:index, :show, :update] do @@ -264,119 +250,6 @@ Rails.application.routes.draw do end end - resources :courses do - member do - get 'settings', action: 'settings', as: 'settings' - post 'set_invite_code_halt' - post 'set_public_or_private' - post 'search_teacher_candidate' - post 'add_teacher' - post 'create_graduation_group' - post 'join_graduation_group' - post 'set_course_group' - post 'change_course_admin' - post 'change_member_role' - post 'change_course_teacher' - post 'delete_course_teacher' - post 'teacher_application_review' - post 'transfer_to_course_group' - post 'delete_from_course' - post 'add_students_by_search' - post 'create_group_by_importing_file' - post 'duplicate_course' - post 'visits_plus_one' - get 'get_historical_courses' - get 'get_historical_course_students' - get 'course_group_list' - get 'add_teacher_popup' - get 'teachers' - get 'apply_teachers' - get 'graduation_group_list' - get 'top_banner' - get 'left_banner' - get 'students' - get 'all_course_groups' - get 'search_users' - get 'base_info' - get 'attahcment_category_list' - get 'export_member_scores_excel' #导出课堂信息 - get 'export_couser_info' - get 'export_member_act_score' - post 'switch_to_teacher' - post 'switch_to_assistant' - post 'switch_to_student' - post 'exit_course' - get 'informs' - post 'update_informs' - post 'new_informs' - delete 'delete_informs' - get 'online_learning' - post 'join_excellent_course' - get 'tasks_list' - post 'update_task_position' - get 'course_groups' - post 'join_course_group' - get 'work_score' - get 'act_score' - get 'statistics' - get 'course_videos' - delete 'delete_course_video' - post :inform_up - post :inform_down - end - - collection do - post 'apply_to_join_course' - post 'search_course_list' - get 'board_list' - get 'mine' - get 'search_slim' - end - - resources :course_stages, shallow: true do - member do - post :up_position - post :down_position - end - end - - resources :course_groups, shallow: true do - member do - post 'rename_group' - post 'move_category' - post 'set_invite_code_halt' - end - end - end - - - resources :course_modules, shallow: true do - member do - get 'sticky_module' - get 'hidden_module' - post 'rename_module' - post 'add_second_category' - end - collection do - post 'unhidden_modules' - end - end - - resources :course_second_categories, shallow: true do - member do - post 'rename_category' - post 'move_category' - end - end - - - resources :repertoires, only: [:index] - - scope module: :projects do - resources :project_applies, only: [:create] - end - - namespace :wechats do resource :js_sdk_signature, only: [:create] end @@ -429,9 +302,208 @@ Rails.application.routes.draw do end end end + + # Project Area START + scope "/:owner/:repo" do + scope do + get( + '/activity', + to: 'project_trends#index', + as: :project_activity + ) + end + + resource :projects, path: '/', except: [:show, :edit] do + member do + get :branches + get :simple + get :watchers, to: 'projects#watch_users' + get :stargazers, to: 'projects#praise_users' + get :members, to: 'projects#fork_users' + match :about, :via => [:get, :put, :post] + end + end + + resource :repositories, path: '/', only: [:show, :create, :edit] do + member do + get :archive + get :top_counts + get :entries + match :sub_entries, :via => [:get, :put] + get :commits + get :tags + post :create_file + put :update_file + delete :delete_file + post :repo_hook + post :sync_mirror + get :top_counts + get 'commits/:sha', to: 'repositories#commit', as: 'commit' + end + end + + resources :issues do + collection do + get :commit_issues + get :index_chosen + post :clean + post :series_update + end + member do + post :copy + post :close_issue + post :lock_issue + end + end + + # compare + resources :compare, only: [:index, :create] + get '/compare/:base...:head' => 'compare#show', :as => 'compare', + :constraints => { base: /.+/, head: /.+/ } + + resources :pull_requests, :path => :pulls, except: [:destroy] do + member do + post :pr_merge + # post :check_merge + post :refuse_merge + get :files + get :commits + end + collection do + post :check_can_merge + get :create_merge_infos + get :get_branches + end + end + + resources :versions, :path => :milestones do + member do + post :update_status + end + end + + resources :members, :path => :collaborators, only: [:index, :create] do + collection do + delete :remove + put :change_role + end + end + + resources :hooks + resources :forks, only: [:create] + resources :project_trends, :path => :activity, only: [:index, :create] + resources :issue_tags, :path => :labels, only: [:create, :edit, :update, :destroy, :index] + resources :version_releases, :path => :releases, only: [:index,:new, :create, :edit, :update, :destroy] + + scope module: :ci do + scope do + match( + 'ci_authorize', + to: 'projects#authorize', + as: :ci_authorize, + :via => [:get, :put] + ) + get( + 'get_trustie_pipeline', + to: 'projects#get_trustie_pipeline', + as: :get_trustie_pipeline + ) + put( + 'update_trustie_pipeline', + to: 'projects#update_trustie_pipeline', + as: :update_trustie_pipeline + ) + post( + 'activate', + to: 'projects#activate', + as: :ci_activate_project + ) + delete( + 'deactivate', + to: 'projects#deactivate', + as: :ci_deactivate_project + ) + end + + resources :cloud_accounts, only: [:create] do + member do + post :activate + delete :deactivate + end + end + resources :builds, param: :build do + member do + post :restart + delete :stop + get '/logs/:stage/:step', to: 'builds#logs', as: 'logs' + end + end + end + + scope module: :projects do + scope do + get( + '/blob/*id/diff', + to: 'blob#diff', + constraints: { id: /.+/, format: false }, + as: :blob_diff + ) + get( + '/blob/*id', + to: 'blob#show', + constraints: { id: /.+/, format: false }, + as: :blob + ) + delete( + '/blob/*id', + to: 'blob#destroy', + constraints: { id: /.+/, format: false } + ) + put( + '/blob/*id', + to: 'blob#update', + constraints: { id: /.+/, format: false } + ) + post( + '/blob/*id', + to: 'blob#create', + constraints: { id: /.+/, format: false } + ) + end + + scope do + get( + '/raw/*id', + to: 'raw#show', + constraints: { id: /.+/, format: /(html|js)/ }, + as: :raw + ) + end + + scope do + get( + '/blame/*id', + to: 'blame#show', + constraints: { id: /.+/, format: /(html|js)/ }, + as: :blame + ) + end + + scope do + get( + '/tree/*id', + to: 'tree#show', + constraints: { id: /.+/, format: /(html|js)/ }, + as: :tree + ) + end + end + end + # Project Area END end namespace :admins do + mount Sidekiq::Web => '/sidekiq' get '/', to: 'dashboards#index' resources :project_statistics, only: [:index] do collection do @@ -612,7 +684,7 @@ Rails.application.routes.draw do post :update_sync_course end - resource :laboratory_setting, only: [:show, :update] + resource :laboratory_setting, only: [:show, :update, :new] resource :laboratory_user, only: [:create, :destroy] resources :carousels, only: [:index, :create, :update, :destroy] do @@ -704,4 +776,6 @@ Rails.application.routes.draw do ## react用 get '*path', to: 'main#index', constraints: ReactConstraint.new + + end diff --git a/db/migrate/20200609100407_change_issue_token.rb b/db/migrate/20200609100407_change_issue_token.rb new file mode 100644 index 00000000..09608dc2 --- /dev/null +++ b/db/migrate/20200609100407_change_issue_token.rb @@ -0,0 +1,5 @@ +class ChangeIssueToken < ActiveRecord::Migration[5.2] + def change + change_column :issues, :token, :integer, default: 0 + end +end diff --git a/db/migrate/20200610071625_remove_issues_lock_version_column.rb b/db/migrate/20200610071625_remove_issues_lock_version_column.rb index 2ec9477a..ffe1a0f9 100644 --- a/db/migrate/20200610071625_remove_issues_lock_version_column.rb +++ b/db/migrate/20200610071625_remove_issues_lock_version_column.rb @@ -2,4 +2,4 @@ class RemoveIssuesLockVersionColumn < ActiveRecord::Migration[5.2] def change remove_column :issues, :lock_version end -end \ No newline at end of file +end diff --git a/db/migrate/20200708114354_create_devops_cloud_accounts.rb b/db/migrate/20200708114354_create_devops_cloud_accounts.rb new file mode 100644 index 00000000..3607968f --- /dev/null +++ b/db/migrate/20200708114354_create_devops_cloud_accounts.rb @@ -0,0 +1,14 @@ +class CreateDevopsCloudAccounts < ActiveRecord::Migration[5.2] + def change + create_table :devops_cloud_accounts do |t| + t.integer :project_id, null: false + t.integer :user_id, null: false + t.integer :ip_num, null: false + t.string :account, null: false + t.string :secret, null: false + + t.timestamps + end + add_index :devops_cloud_accounts, [:project_id, :user_id, :ip_num] + end +end diff --git a/db/migrate/20200709061656_add_gitea_oauth_id_and_project_id_to_oauths.rb b/db/migrate/20200709061656_add_gitea_oauth_id_and_project_id_to_oauths.rb new file mode 100644 index 00000000..6208601b --- /dev/null +++ b/db/migrate/20200709061656_add_gitea_oauth_id_and_project_id_to_oauths.rb @@ -0,0 +1,6 @@ +class AddGiteaOauthIdAndProjectIdToOauths < ActiveRecord::Migration[5.2] + def change + add_column :oauths, :gitea_oauth_id, :integer + add_column :oauths, :project_id, :integer + end +end diff --git a/db/migrate/20200710124116_create_dev_ops_languages.rb b/db/migrate/20200710124116_create_dev_ops_languages.rb new file mode 100644 index 00000000..1a899ad0 --- /dev/null +++ b/db/migrate/20200710124116_create_dev_ops_languages.rb @@ -0,0 +1,11 @@ +class CreateDevOpsLanguages < ActiveRecord::Migration[5.2] + def change + create_table :dev_ops_languages do |t| + t.string :name, null: false, comment: 'The name of project language.' + t.text :content, null: false, comment: 'The content of project language.' + t.integer :usage_amount, default: 0, comment: 'number of people Using the language' + + t.timestamps + end + end +end diff --git a/db/migrate/20200713150706_create_dev_ops_cloud_accounts.rb b/db/migrate/20200713150706_create_dev_ops_cloud_accounts.rb new file mode 100644 index 00000000..3351ab39 --- /dev/null +++ b/db/migrate/20200713150706_create_dev_ops_cloud_accounts.rb @@ -0,0 +1,14 @@ +class CreateDevOpsCloudAccounts < ActiveRecord::Migration[5.2] + def change + create_table :dev_ops_cloud_accounts do |t| + t.integer :project_id, null: false + t.integer :user_id, null: false + t.integer :ip_num + t.string :account + t.string :secret + + t.timestamps + end + add_index :dev_ops_cloud_accounts, [:project_id, :user_id, :ip_num], name: 'dev_ops_cloud_accounts_p_u_ip' + end +end diff --git a/db/migrate/20200714014513_add_cover_id_to_dev_ops_languages.rb b/db/migrate/20200714014513_add_cover_id_to_dev_ops_languages.rb new file mode 100644 index 00000000..6e88bfa2 --- /dev/null +++ b/db/migrate/20200714014513_add_cover_id_to_dev_ops_languages.rb @@ -0,0 +1,5 @@ +class AddCoverIdToDevOpsLanguages < ActiveRecord::Migration[5.2] + def change + add_column :dev_ops_languages, :cover_id, :integer + end +end diff --git a/db/migrate/20200714032759_drop_devops_clound_accounts_table.rb b/db/migrate/20200714032759_drop_devops_clound_accounts_table.rb new file mode 100644 index 00000000..d0bfb6f8 --- /dev/null +++ b/db/migrate/20200714032759_drop_devops_clound_accounts_table.rb @@ -0,0 +1,5 @@ +class DropDevopsCloundAccountsTable < ActiveRecord::Migration[5.2] + def change + drop_table(:devops_cloud_accounts) if ActiveRecord::Base.connection.tables.include?('devops_cloud_accounts') + end +end diff --git a/db/migrate/20200714072948_add_open_devops_to_projects.rb b/db/migrate/20200714072948_add_open_devops_to_projects.rb new file mode 100644 index 00000000..0d189aa5 --- /dev/null +++ b/db/migrate/20200714072948_add_open_devops_to_projects.rb @@ -0,0 +1,5 @@ +class AddOpenDevopsToProjects < ActiveRecord::Migration[5.2] + def change + add_column :projects, :open_devops, :boolean, default: false + end +end diff --git a/db/migrate/20200714112206_add_drone_token_to_dev_ops_cloud_accounts.rb b/db/migrate/20200714112206_add_drone_token_to_dev_ops_cloud_accounts.rb new file mode 100644 index 00000000..f777fde2 --- /dev/null +++ b/db/migrate/20200714112206_add_drone_token_to_dev_ops_cloud_accounts.rb @@ -0,0 +1,5 @@ +class AddDroneTokenToDevOpsCloudAccounts < ActiveRecord::Migration[5.2] + def change + add_column :dev_ops_cloud_accounts, :drone_token, :string + end +end 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 00000000..af42232e --- /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 diff --git a/db/migrate/20200715152711_change_description_limt_from_issues.rb b/db/migrate/20200715152711_change_description_limt_from_issues.rb new file mode 100644 index 00000000..ca98a5ae --- /dev/null +++ b/db/migrate/20200715152711_change_description_limt_from_issues.rb @@ -0,0 +1,5 @@ +class ChangeDescriptionLimtFromIssues < ActiveRecord::Migration[5.2] + def change + change_column :issues, :description, :longtext + end +end diff --git a/db/migrate/20200716060536_change_projects_default_count.rb b/db/migrate/20200716060536_change_projects_default_count.rb new file mode 100644 index 00000000..858cd8fd --- /dev/null +++ b/db/migrate/20200716060536_change_projects_default_count.rb @@ -0,0 +1,13 @@ +class ChangeProjectsDefaultCount < ActiveRecord::Migration[5.2] + def change + projects = Project.select(:id, :issues_count,:pull_requests_count,:versions_count,:praises_count,:watchers_count).all + projects.each do |p| + puts p.id + # Project.reset_counters( p.id, :issues_count, touch: false ) + Project.reset_counters( p.id, :pull_requests_count, touch: false ) + Project.reset_counters( p.id, :versions_count, touch: false ) + # Project.reset_counters( p.id, :praises_count, touch: false ) + Project.reset_counters( p.id, :watchers_count, touch: false ) + end + end +end diff --git a/db/migrate/20200717015216_change_versions_issues_count.rb b/db/migrate/20200717015216_change_versions_issues_count.rb new file mode 100644 index 00000000..b0755bfd --- /dev/null +++ b/db/migrate/20200717015216_change_versions_issues_count.rb @@ -0,0 +1,15 @@ +class ChangeVersionsIssuesCount < ActiveRecord::Migration[5.2] + def change + versions = Version.includes(:issues).select(:id, :closed_issues_count, :percent,:issues_count) + versions.each do |v| + closed_issues = Issue.select(:id, :fixed_version_id, :status_id).where(fixed_version_id: v.id, status_id: 5).size + unless v.closed_issues_count.to_i == closed_issues + puts v.id + percent = v.issues_count.to_i <=0 ? 0.0 : (closed_issues.to_f / v.issues_count.to_i) + v.closed_issues_count = closed_issues + v.percent = percent + v.save + end + end + end +end diff --git a/db/migrate/20200731073851_add_devops_step_to_users.rb b/db/migrate/20200731073851_add_devops_step_to_users.rb new file mode 100644 index 00000000..6815b797 --- /dev/null +++ b/db/migrate/20200731073851_add_devops_step_to_users.rb @@ -0,0 +1,5 @@ +class AddDevopsStepToUsers < ActiveRecord::Migration[5.2] + def change + add_column :users, :devops_step, :integer, default: 0, comment: '0: uninit devops; 1: unverified; 2: verified' + end +end diff --git a/db/migrate/20200813144941_rename_dev_ops_cloud_account_to_ci_cloud_account.rb b/db/migrate/20200813144941_rename_dev_ops_cloud_account_to_ci_cloud_account.rb new file mode 100644 index 00000000..2fcc477a --- /dev/null +++ b/db/migrate/20200813144941_rename_dev_ops_cloud_account_to_ci_cloud_account.rb @@ -0,0 +1,5 @@ +class RenameDevOpsCloudAccountToCiCloudAccount < ActiveRecord::Migration[5.2] + def change + rename_table :dev_ops_cloud_accounts, :ci_cloud_accounts + end +end diff --git a/db/migrate/20200813150315_rename_dev_ops_language_to_ci_language.rb b/db/migrate/20200813150315_rename_dev_ops_language_to_ci_language.rb new file mode 100644 index 00000000..47361838 --- /dev/null +++ b/db/migrate/20200813150315_rename_dev_ops_language_to_ci_language.rb @@ -0,0 +1,5 @@ +class RenameDevOpsLanguageToCiLanguage < ActiveRecord::Migration[5.2] + def change + rename_table :dev_ops_languages, :ci_languages + end +end diff --git a/db/migrate/20200828021007_add_ci_user_id_to_ci_cloud_accounts.rb b/db/migrate/20200828021007_add_ci_user_id_to_ci_cloud_accounts.rb new file mode 100644 index 00000000..6fe4f7a6 --- /dev/null +++ b/db/migrate/20200828021007_add_ci_user_id_to_ci_cloud_accounts.rb @@ -0,0 +1,5 @@ +class AddCiUserIdToCiCloudAccounts < ActiveRecord::Migration[5.2] + def change + add_column :ci_cloud_accounts, :ci_user_id, :integer + end +end diff --git a/db/migrate/20200828022021_remove_project_id_from_ci_cloud_accounts.rb b/db/migrate/20200828022021_remove_project_id_from_ci_cloud_accounts.rb new file mode 100644 index 00000000..580083bf --- /dev/null +++ b/db/migrate/20200828022021_remove_project_id_from_ci_cloud_accounts.rb @@ -0,0 +1,7 @@ +class RemoveProjectIdFromCiCloudAccounts < ActiveRecord::Migration[5.2] + def change + remove_column :ci_cloud_accounts, :project_id + remove_column :ci_cloud_accounts, :repo_id + remove_column :ci_cloud_accounts, :drone_token + end +end diff --git a/db/migrate/20200904074907_add_gitea_webhook_id_to_projects.rb b/db/migrate/20200904074907_add_gitea_webhook_id_to_projects.rb new file mode 100644 index 00000000..35ba3e28 --- /dev/null +++ b/db/migrate/20200904074907_add_gitea_webhook_id_to_projects.rb @@ -0,0 +1,5 @@ +class AddGiteaWebhookIdToProjects < ActiveRecord::Migration[5.2] + def change + add_column :projects, :gitea_webhook_id, :integer + end +end diff --git a/db/migrate/20200925090122_add_open_devops_count_to_projects.rb b/db/migrate/20200925090122_add_open_devops_count_to_projects.rb new file mode 100644 index 00000000..9150b267 --- /dev/null +++ b/db/migrate/20200925090122_add_open_devops_count_to_projects.rb @@ -0,0 +1,5 @@ +class AddOpenDevopsCountToProjects < ActiveRecord::Migration[5.2] + def change + add_column :projects, :open_devops_count, :integer, default: 0, comment: '针对同一台ci服务器激活devops流程的次数' + end +end diff --git a/db/migrate/20200927023922_reset_versions_count.rb b/db/migrate/20200927023922_reset_versions_count.rb new file mode 100644 index 00000000..2c121e62 --- /dev/null +++ b/db/migrate/20200927023922_reset_versions_count.rb @@ -0,0 +1,17 @@ +class ResetVersionsCount < ActiveRecord::Migration[5.2] + def change + execute "ALTER TABLE licenses MODIFY COLUMN id INT AUTO_INCREMENT;" + versions = Version.includes(:issues).select(:id, :closed_issues_count, :percent,:issues_count) + versions.each do |v| + Version.reset_counters v.id, :issues + closed_issues = Issue.select(:id, :fixed_version_id, :status_id).where(fixed_version_id: v.id, status_id: 5).size + unless v.closed_issues_count.to_i == closed_issues + percent = v.issues_count.to_i <=0 ? 0.0 : (closed_issues.to_f / v.issues_count.to_i) + v.closed_issues_count = closed_issues + v.percent = percent + v.save + end + puts v.id + end + end +end diff --git a/db/migrate/20200929062837_add_index_to_users_type.rb b/db/migrate/20200929062837_add_index_to_users_type.rb new file mode 100644 index 00000000..d27ca9dd --- /dev/null +++ b/db/migrate/20200929062837_add_index_to_users_type.rb @@ -0,0 +1,5 @@ +class AddIndexToUsersType < ActiveRecord::Migration[5.2] + def change + add_index :users, :type + end +end diff --git a/db/migrate/20201004034434_add_recommend_to_projects.rb b/db/migrate/20201004034434_add_recommend_to_projects.rb new file mode 100644 index 00000000..d00b3eb6 --- /dev/null +++ b/db/migrate/20201004034434_add_recommend_to_projects.rb @@ -0,0 +1,5 @@ +class AddRecommendToProjects < ActiveRecord::Migration[5.2] + def change + add_column :projects, :recommend, :boolean, default: false + end +end diff --git a/db/migrate/20201004070431_create_project_details.rb b/db/migrate/20201004070431_create_project_details.rb new file mode 100644 index 00000000..09b63bd6 --- /dev/null +++ b/db/migrate/20201004070431_create_project_details.rb @@ -0,0 +1,12 @@ +class CreateProjectDetails < ActiveRecord::Migration[5.2] + def change + create_table :project_details do |t| + t.integer :project_id + t.longtext :content + + t.timestamps + end + + add_index :project_details, :project_id + end +end diff --git a/db/migrate/20201019082617_add_platform_to_projects.rb b/db/migrate/20201019082617_add_platform_to_projects.rb new file mode 100644 index 00000000..0301a13c --- /dev/null +++ b/db/migrate/20201019082617_add_platform_to_projects.rb @@ -0,0 +1,5 @@ +class AddPlatformToProjects < ActiveRecord::Migration[5.2] + def change + add_column :projects, :platform, :integer, default: 0 + end +end diff --git a/db/migrate/20201019104433_create_project_educoders.rb b/db/migrate/20201019104433_create_project_educoders.rb new file mode 100644 index 00000000..e80d9711 --- /dev/null +++ b/db/migrate/20201019104433_create_project_educoders.rb @@ -0,0 +1,12 @@ +class CreateProjectEducoders < ActiveRecord::Migration[5.2] + def change + create_table :project_educoders do |t| + t.string :owner + t.string :repo_name + t.string :image_url + t.integer :project_id + + t.timestamps + end + end +end diff --git a/db/migrate/20201020071758_change_description_from_projects.rb b/db/migrate/20201020071758_change_description_from_projects.rb new file mode 100644 index 00000000..9c4e3350 --- /dev/null +++ b/db/migrate/20201020071758_change_description_from_projects.rb @@ -0,0 +1,5 @@ +class ChangeDescriptionFromProjects < ActiveRecord::Migration[5.2] + def change + change_column :projects, :description, :longtext + end +end diff --git a/db/migrate/20201020083709_add_index_to_projects.rb b/db/migrate/20201020083709_add_index_to_projects.rb new file mode 100644 index 00000000..b968a17c --- /dev/null +++ b/db/migrate/20201020083709_add_index_to_projects.rb @@ -0,0 +1,5 @@ +class AddIndexToProjects < ActiveRecord::Migration[5.2] + def change + add_index :projects, :identifier, name: 'index_projects_on_identifier' + end +end diff --git a/db/migrate/20201020093834_add_forked_count_and_commit_count_to_project_educoders.rb b/db/migrate/20201020093834_add_forked_count_and_commit_count_to_project_educoders.rb new file mode 100644 index 00000000..d49b1e39 --- /dev/null +++ b/db/migrate/20201020093834_add_forked_count_and_commit_count_to_project_educoders.rb @@ -0,0 +1,6 @@ +class AddForkedCountAndCommitCountToProjectEducoders < ActiveRecord::Migration[5.2] + def change + add_column :project_educoders, :commit_count, :integer, default: 0 + add_column :project_educoders, :forked_count, :integer, default: 0 + end +end diff --git a/db/migrate/20201021031915_create_project_statistics.rb b/db/migrate/20201021031915_create_project_statistics.rb new file mode 100644 index 00000000..c266816d --- /dev/null +++ b/db/migrate/20201021031915_create_project_statistics.rb @@ -0,0 +1,12 @@ +class CreateProjectStatistics < ActiveRecord::Migration[5.2] + def change + create_table :project_statistics do |t| + t.integer :common_projects_count, :default => 0 + t.integer :mirror_projects_count, :default => 0 + t.integer :sync_mirror_projects_count, :default => 0 + t.integer :commits_total_count, :default => 0 + + t.timestamps + end + end +end diff --git a/db/migrate/20201021033117_add_index_for_project_type_to_projects.rb b/db/migrate/20201021033117_add_index_for_project_type_to_projects.rb new file mode 100644 index 00000000..f86edc38 --- /dev/null +++ b/db/migrate/20201021033117_add_index_for_project_type_to_projects.rb @@ -0,0 +1,5 @@ +class AddIndexForProjectTypeToProjects < ActiveRecord::Migration[5.2] + def change + add_index :projects, :project_type + end +end diff --git a/db/migrate/20201021041202_add_index_for_updated_on_to_projects.rb b/db/migrate/20201021041202_add_index_for_updated_on_to_projects.rb new file mode 100644 index 00000000..43c223a6 --- /dev/null +++ b/db/migrate/20201021041202_add_index_for_updated_on_to_projects.rb @@ -0,0 +1,5 @@ +class AddIndexForUpdatedOnToProjects < ActiveRecord::Migration[5.2] + def change + add_index :projects, :updated_on + end +end diff --git a/db/migrate/20201021070524_add_some_index_to_projects.rb b/db/migrate/20201021070524_add_some_index_to_projects.rb new file mode 100644 index 00000000..47a3c2fd --- /dev/null +++ b/db/migrate/20201021070524_add_some_index_to_projects.rb @@ -0,0 +1,11 @@ +class AddSomeIndexToProjects < ActiveRecord::Migration[5.2] + def change + add_index :projects, :project_category_id + add_index :projects, :project_language_id + add_index :projects, :is_public + add_index :projects, :status + add_index :projects, :forked_from_project_id + add_index :projects, :recommend + add_index :projects, :platform + end +end diff --git a/db/migrate/20201021080638_add_user_id_index_to_projects.rb b/db/migrate/20201021080638_add_user_id_index_to_projects.rb new file mode 100644 index 00000000..63edfbbc --- /dev/null +++ b/db/migrate/20201021080638_add_user_id_index_to_projects.rb @@ -0,0 +1,6 @@ +class AddUserIdIndexToProjects < ActiveRecord::Migration[5.2] + def change + add_index :projects, :user_id + add_index :projects, :name + end +end diff --git a/db/migrate/20201022164823_add_index_for_project_id_to_project_educoders.rb b/db/migrate/20201022164823_add_index_for_project_id_to_project_educoders.rb new file mode 100644 index 00000000..232c8055 --- /dev/null +++ b/db/migrate/20201022164823_add_index_for_project_id_to_project_educoders.rb @@ -0,0 +1,6 @@ +class AddIndexForProjectIdToProjectEducoders < ActiveRecord::Migration[5.2] + def change + add_index :project_educoders, :repo_name + add_index :project_educoders, :project_id + end +end diff --git a/db/migrate/20201023025821_remove_index_from_projects.rb b/db/migrate/20201023025821_remove_index_from_projects.rb new file mode 100644 index 00000000..783b9587 --- /dev/null +++ b/db/migrate/20201023025821_remove_index_from_projects.rb @@ -0,0 +1,7 @@ +class RemoveIndexFromProjects < ActiveRecord::Migration[5.2] + def change + remove_index :projects, :project_language_id + remove_index :projects, :project_category_id + remove_index :projects, :user_id + end +end diff --git a/db/migrate/20201104034658_add_commits_count_and_files_count_to_pull_requests.rb b/db/migrate/20201104034658_add_commits_count_and_files_count_to_pull_requests.rb new file mode 100644 index 00000000..f84da29f --- /dev/null +++ b/db/migrate/20201104034658_add_commits_count_and_files_count_to_pull_requests.rb @@ -0,0 +1,7 @@ +class AddCommitsCountAndFilesCountToPullRequests < ActiveRecord::Migration[5.2] + def change + add_column :pull_requests, :comments_count, :integer, default: 0, comment: 'number of comments for pull request' + add_column :pull_requests, :commits_count, :integer, default: 0, comment: 'number of git commits for pull request' + add_column :pull_requests, :files_count, :integer, default: 0, comment: 'number of git change files for pull request' + end +end diff --git a/db/seeds.rb b/db/seeds.rb index c5169d6b..4d231253 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -28,4 +28,550 @@ # vod_status: "uploaded", # published_at: nil, # filesize: 14877403 -# } \ No newline at end of file +# } + +# mm = "drwxrwx--- 63 git git 4096 4月 21 18:23 jacknudt +# drwxrws--- 51 git git 4096 4月 21 18:23 linchun +# drwxrwx--- 8 git git 141 4月 21 18:23 jiangdami +# drwxrws--- 10 git git 208 4月 21 18:23 yeshifuo +# drwxrwx--- 6 git git 82 4月 21 18:23 xtom598 +# drwxrwx--- 16 git git 4096 4月 21 18:23 ladventure +# drwxrwx--- 6 git git 89 4月 21 18:23 whcunzhang +# drwxrws--- 8 git git 159 4月 21 18:23 xuzhen +# drwxrws--- 8 git git 159 4月 21 18:23 yinkang +# drwxrws--- 8 git git 164 4月 21 18:23 mingholy +# drwxrws--- 7 git git 142 4月 21 18:23 qiaoyang +# drwxrws--- 6 git git 91 4月 21 18:23 ttskym +# drwxrwx--- 8 git git 167 4月 21 18:23 megan +# drwxrwx--- 7 git git 143 4月 21 18:23 wc +# drwxrwx--- 7 git git 138 4月 21 18:23 kakawei +# drwxrwx--- 9 git git 183 4月 21 18:23 liqing +# drwxrws--- 10 git git 196 4月 21 18:23 zym +# drwxrwx--- 9 git git 218 4月 21 18:23 zengqx +# drwxrws--- 6 git git 102 4月 21 18:23 scuwangjianfei +# drwxrws--- 5 git git 70 4月 21 18:23 wzz +# drwxrwx--- 10 git git 203 4月 21 18:23 yaopan +# drwxrws--- 12 git git 243 4月 21 18:23 lifan +# drwxrwx--- 19 git git 4096 4月 21 18:23 lifu +# drwxrws--- 5 git git 77 4月 21 18:23 tzshede +# drwxrwx--- 2 git git 6 4月 22 14:32 asmallsun +# drwxrwx--- 2 git git 6 4月 22 14:33 cpr123 +# drwxrwx--- 2 git git 6 4月 22 14:51 benny +# drwxrwx--- 2 git git 6 4月 22 14:51 blgwq +# drwxrwx--- 2 git git 6 4月 22 15:02 daijingyi +# drwxrwx--- 2 git git 6 4月 22 16:25 gxm2019112207 +# drwxrwx--- 2 git git 6 4月 22 17:00 Ch1017 +# drwxrwx--- 2 git git 6 4月 22 17:11 future1 +# drwxrwx--- 2 git git 6 4月 22 17:13 flourish +# drwxrwx--- 2 git git 6 4月 22 18:03 Eliauk +# drwxrwx--- 2 git git 6 4月 22 18:38 chenyao333 +# drwxrwx--- 2 git git 6 4月 22 19:23 asdzxc +# drwxrwx--- 2 git git 6 4月 22 19:36 apply +# drwxrwx--- 2 git git 6 4月 22 19:48 Awin +# drwxrwx--- 2 git git 6 4月 22 19:58 fangning +# drwxrwx--- 2 git git 6 4月 22 20:57 DevilLi +# drwxrwx--- 2 git git 6 4月 22 21:07 dengjuan +# drwxrwx--- 2 git git 6 4月 22 22:10 dandelionl +# drwxrwx--- 2 git git 6 4月 23 01:38 a857 +# drwxrwx--- 2 git git 6 4月 23 22:46 Azaurr +# drwxrwx--- 3 git git 21 4月 28 15:33 ALPNAP +# drwxr-xr-x 3 git git 33 4月 28 16:49 jiaozi211 +# drwxr-xr-x 4 git git 54 5月 6 14:33 ff123 +# drwxrwx--- 2 git git 6 5月 7 16:15 anhriuiq +# drwxr-xr-x 4 git git 41 5月 9 09:41 coderfch +# drwxrwx--- 2 git git 6 5月 11 22:52 Ethan4 +# drwxrwx--- 2 git git 6 5月 11 22:57 enable +# drwxrwx--- 2 git git 6 5月 12 12:01 doublecircle +# drwxrwx--- 2 git git 6 5月 12 13:54 gaolongfei +# drwxrwx--- 2 git git 6 5月 12 14:46 crystal0 +# drwxrwx--- 2 git git 6 5月 22 12:47 gujiaxiang +# drwxrwx--- 2 git git 6 5月 22 12:47 Freshwinds +# drwxrwx--- 2 git git 6 5月 22 12:47 atong97 +# drwxrwx--- 2 git git 6 5月 22 12:47 AriesYao +# drwxrwx--- 2 git git 6 5月 29 10:41 Arif +# drwxrwx--- 2 git git 6 5月 30 13:30 druks +# drwxrws--- 5 git git 65 6月 1 19:54 fangquntian +# drwxrwx--- 8 git git 160 6月 9 20:19 qyzh1996 +# drwxrwx--- 2 git git 6 6月 13 11:26 Gany +# drwxrwx--- 3 git git 22 6月 20 23:39 FadePeople +# drwxrwx--- 3 git git 27 6月 24 10:20 xiangliangliang +# drwxrwx--- 2 git git 6 6月 27 11:42 a1s2d3 +# drwxrws--- 4 git git 41 6月 27 16:45 Althur +# drwxrwx--- 2 git git 6 6月 28 05:04 a151811 +# drwxrwx--- 6 git git 77 7月 1 15:01 jiangfeng +# drwxrwx--- 2 git git 6 7月 1 15:03 llha +# drwxr-xr-x 2 git git 6 7月 1 16:36 chris1002 +# drwxrwx--- 2 git git 6 7月 7 13:37 a233 +# drwxrwx--- 2 git git 6 7月 9 14:30 alang +# drwxr-xr-x 4 git git 42 7月 12 21:39 charleszcq +# drwxrws--- 9 git git 198 7月 15 01:44 luojiwen +# drwxrwx--- 9 git git 174 7月 15 01:44 wrm1995 +# drwxrwx--- 4 git git 67 7月 15 01:44 whj +# drwxr-xr-x 3 git git 46 7月 15 01:44 xinwuyaqu +# drwxr-xr-x 3 git git 46 7月 15 01:44 azaurr +# drwxrwx--- 3 git git 46 7月 15 01:44 xpcivelon +# drwxr-xr-x 3 git git 46 7月 15 01:44 wangjichuan +# drwxrwx--- 15 git git 313 7月 15 01:44 hushasha +# drwxr-xr-x 3 git git 46 7月 15 01:44 dreacter +# drwxrwx--- 31 git git 4096 7月 15 01:45 qiubing +# drwxrwx--- 14 git git 237 7月 15 01:45 net +# drwxrwx--- 5 git git 70 7月 15 01:45 zhao2017 +# drwxrws--- 4 git git 47 7月 15 01:45 littlefinger +# drwxrws--- 3 git git 46 7月 15 01:45 vainglory +# drwxr-xr-x 3 git git 46 7月 15 01:45 yk +# drwxr-xr-x 5 git git 76 7月 15 01:45 connolly +# drwxrwx--- 3 git git 46 7月 15 01:45 robin_shaun +# drwxrwx--- 3 git git 46 7月 15 01:45 xunhan +# drwxr-xr-x 3 git git 46 7月 15 01:45 majj +# drwxr-xr-x 3 git git 46 7月 15 01:45 strawer +# drwxr-xr-x 3 git git 46 7月 15 01:45 hyp19991114 +# drwxr-xr-x 3 git git 46 7月 15 01:45 msydoe +# drwxr-xr-x 3 git git 46 7月 15 01:45 sukifly +# drwxr-xr-x 3 git git 46 7月 15 01:45 aning +# drwxr-xr-x 3 git git 46 7月 15 01:45 sansuiqiang +# drwxr-xr-x 3 git git 46 7月 15 01:45 chenhuadust +# drwxr-xr-x 3 git git 46 7月 15 01:45 steph +# drwxr-xr-x 4 git git 86 7月 15 01:45 xusongxu +# drwxr-xr-x 100 git git 4096 7月 15 01:45 hjqreturn +# drwxr-xr-x 3 git git 46 7月 15 01:45 lap123 +# drwxr-xr-x 3 git git 46 7月 15 01:45 aaaaaaries +# drwxr-xr-x 3 git git 46 7月 15 01:45 jiroo +# drwxr-xr-x 3 git git 46 7月 15 01:45 zwhmily +# drwxr-xr-x 3 git git 46 7月 15 01:45 ye0000 +# drwxr-xr-x 3 git git 46 7月 15 01:45 ffnudt +# drwxrwx--- 3 git git 46 7月 15 01:45 madehong +# drwxr-xr-x 4 git git 41 7月 15 01:45 althur +# drwxr-xr-x 7 git git 206 7月 15 01:45 linbojue +# drwxr-xr-x 3 git git 46 7月 15 01:45 kevinl +# drwxrws--- 25 git git 4096 7月 15 01:45 young +# drwxr-xr-x 3 git git 46 7月 15 01:45 mj2333 +# drwxrwx--- 3 git git 46 7月 15 01:45 zhaijianyang +# drwxrws--- 6 git git 127 7月 15 01:45 lexi +# drwxrwx--- 3 git git 46 7月 15 01:45 wangfang1 +# drwxr-xr-x 4 git git 61 7月 15 01:45 alpnap +# drwxrws--- 108 git git 4096 7月 15 01:45 starlee +# drwxrws--- 4 git git 44 7月 15 01:45 zmiracle +# drwxr-xr-x 3 git git 26 7月 15 23:56 hjl4am +# drwxr-xr-x 6 git git 142 7月 15 23:57 fadepeople +# drwxr-xr-x 3 git git 24 7月 16 10:45 wangliang +# drwxr-xr-x 4 git git 55 7月 16 20:24 transcendence +# drwxr-xr-x 2 git git 6 7月 17 14:08 royiwen +# drwxrws--- 4 git git 52 7月 17 18:34 dengxiang +# drwxrws--- 4 git git 44 7月 17 18:34 chykd +# drwxrws--- 4 git git 48 7月 17 18:34 chensen +# drwxrws--- 3 git git 28 7月 17 18:34 buyaolian +# drwxrws--- 3 git git 27 7月 17 18:34 go2school +# drwxrws--- 4 git git 52 7月 17 18:34 doublezhang +# drwxrws--- 3 git git 27 7月 17 18:34 dingyan +# drwxrws--- 6 git git 86 7月 17 18:34 fiona98 +# drwxrws--- 3 git git 27 7月 17 18:34 254282288 +# drwxrws--- 3 git git 33 7月 17 18:34 cs_melody +# drwxrws--- 3 git git 27 7月 17 18:34 446117802 +# drwxrws--- 3 git git 23 7月 17 18:34 296769150 +# drwxrws--- 3 git git 27 7月 17 18:34 flycutter +# drwxrws--- 3 git git 27 7月 17 18:34 645305914 +# drwxrws--- 3 git git 34 7月 17 18:34 brikeylee +# drwxrws--- 13 git git 239 7月 17 18:34 ccccx +# drwxrws--- 4 git git 40 7月 17 18:34 chychenhongyi +# drwxrws--- 4 git git 48 7月 17 18:34 cjw12345 +# drwxrws--- 3 git git 27 7月 17 18:34 chenyi +# drwxrws--- 3 git git 22 7月 17 18:34 gl2013 +# drwxrws--- 5 git git 61 7月 17 18:34 airwings +# drwxrws--- 3 git git 27 7月 17 18:34 blackgod +# drwxrws--- 3 git git 27 7月 17 18:34 bxyybxx +# drwxrws--- 4 git git 47 7月 17 18:34 dushiyin +# drwxrws--- 3 git git 22 7月 17 18:34 dengtengjiao +# drwxrws--- 3 git git 27 7月 17 18:34 aipeng +# drwxrws--- 3 git git 27 7月 17 18:34 gaomali +# drwxrws--- 3 git git 27 7月 17 18:34 chaanyean +# drwxrws--- 3 git git 27 7月 17 18:34 alanlong +# drwxrws--- 5 git git 70 7月 17 18:34 a1508248159 +# drwxrws--- 3 git git 30 7月 17 18:34 gcs122 +# drwxrws--- 4 git git 37 7月 17 18:34 962445223 +# drwxrws--- 5 git git 64 7月 17 18:34 cxhssg0 +# drwxrws--- 5 git git 68 7月 17 18:34 alan +# drwxrws--- 3 git git 27 7月 17 18:34 chenyi123 +# drwxrws--- 3 git git 27 7月 17 18:35 caixiang +# drwxrws--- 5 git git 74 7月 17 18:35 fenghenda +# drwxrws--- 3 git git 27 7月 17 18:35 201509066016 +# drwxrws--- 3 git git 27 7月 17 18:35 dongshuai11 +# drwxrws--- 3 git git 27 7月 17 18:35 745691375 +# drwxrws--- 3 git git 27 7月 17 18:35 crack521 +# drwxrws--- 5 git git 74 7月 17 18:35 demostudent +# drwxrws--- 5 git git 84 7月 17 18:35 girlinmymirror +# drwxrws--- 3 git git 27 7月 17 18:35 baobao44 +# drwxrws--- 4 git git 36 7月 17 18:35 2013551828 +# drwxrws--- 3 git git 27 7月 17 18:35 chenzhongwei15 +# drwxrws--- 4 git git 48 7月 17 18:35 chen834768 +# drwxrws--- 3 git git 27 7月 17 18:35 explorer +# drwxrws--- 7 git git 143 7月 17 18:35 fool +# drwxrws--- 3 git git 27 7月 17 18:35 561513726 +# drwxrws--- 3 git git 27 7月 17 18:35 dengxuelei11 +# drwxrws--- 5 git git 73 7月 17 18:35 cjy19951215 +# drwxrws--- 4 git git 47 7月 17 18:35 123txy +# drwxrws--- 3 git git 27 7月 17 18:35 201206020025 +# drwxrws--- 7 git git 134 7月 17 18:35 bingxia +# drwxrws--- 4 git git 52 7月 17 18:35 alin3217 +# drwxrwx--- 3 git git 27 7月 17 18:35 a45678 +# drwxrws--- 3 git git 27 7月 17 18:35 1012159603 +# drwxrws--- 7 git git 112 7月 17 18:35 chancy +# drwxrws--- 3 git git 27 7月 17 18:35 duanguangjun +# drwxrws--- 5 git git 97 7月 17 18:35 b411763600 +# drwxrws--- 3 git git 24 7月 17 18:35 fzddtc +# drwxrws--- 3 git git 27 7月 17 18:35 dingdong +# drwxrws--- 3 git git 27 7月 17 18:35 gebinbin +# drwxrwx--- 3 git git 27 7月 17 18:35 ash123 +# drwxrws--- 16 git git 4096 7月 17 18:35 chenming85 +# drwxrws--- 3 git git 27 7月 17 18:35 guocheng08 +# drwxrws--- 4 git git 47 7月 17 18:35 201206021009 +# drwxrws--- 4 git git 42 7月 17 18:35 ccrystal +# drwxrws--- 3 git git 27 7月 17 18:35 1455182184 +# drwxrws--- 4 git git 58 7月 17 18:35 fox +# drwxrws--- 4 git git 52 7月 17 18:35 chenbotao +# drwxrws--- 3 git git 22 7月 17 18:35 dongguochao +# drwxrws--- 3 git git 20 7月 17 18:35 dmucms +# drwxrws--- 3 git git 33 7月 17 18:35 cuili +# drwxrwx--- 3 git git 27 7月 17 18:35 h7777777 +# drwxrws--- 3 git git 24 7月 17 18:35 fengying +# drwxrws--- 3 git git 27 7月 17 18:37 chenchunyu11 +# drwxrws--- 3 git git 27 7月 17 18:37 axiaobi +# drwxrws--- 3 git git 27 7月 17 18:37 292850825 +# drwxrws--- 3 git git 22 7月 17 18:37 can_be_used +# drwxrws--- 5 git git 82 7月 17 18:37 201528014227051 +# drwxrws--- 4 git git 48 7月 17 18:37 biggerbrain +# drwxrws--- 4 git git 52 7月 17 18:37 adjecverb +# drwxrws--- 5 git git 73 7月 17 18:37 dr1dr1dr1 +# drwxrws--- 3 git git 27 7月 17 18:37 delete +# drwxrws--- 4 git git 50 7月 17 18:37 546251617 +# drwxrws--- 3 git git 27 7月 17 18:37 gaoang +# drwxrws--- 3 git git 27 7月 17 18:37 ace1one +# drwxrws--- 3 git git 22 7月 17 18:37 28376149 +# drwxrwx--- 4 git git 60 7月 17 18:37 cuicuo +# drwxrws--- 3 git git 27 7月 17 18:37 141 +# drwxrws--- 5 git git 68 7月 17 18:37 chenshengling +# drwxrws--- 6 git git 88 7月 17 18:37 1010041109 +# drwxrws--- 3 git git 27 7月 17 18:37 201109060047 +# drwxrws--- 4 git git 54 7月 17 18:37 gy_way +# drwxrws--- 3 git git 27 7月 17 18:37 cryhnuc +# drwxrws--- 3 git git 27 7月 17 18:38 gnleaf +# drwxrws--- 3 git git 27 7月 17 18:38 15066082 +# drwxrws--- 7 git git 138 7月 17 18:38 a1979468 +# drwxrws--- 13 git git 225 7月 17 18:38 389370191 +# drwxrws--- 5 git git 61 7月 17 18:38 goneaway +# drwxrws--- 3 git git 27 7月 17 18:38 2013551629 +# drwxrws--- 4 git git 48 7月 17 18:38 fstdy +# drwxrws--- 4 git git 42 7月 17 18:38 201206043011 +# drwxrws--- 3 git git 21 7月 17 18:38 987654321 +# drwxrws--- 6 git git 88 7月 17 18:38 billcode +# drwxrws--- 4 git git 48 7月 17 18:38 1150478143 +# drwxrws--- 4 git git 48 7月 17 18:38 guohaotian +# drwxrws--- 3 git git 27 7月 17 18:38 ellen +# drwxrws--- 10 git git 254 7月 17 18:38 cgao +# drwxrws--- 4 git git 52 7月 17 18:38 changyan17 +# drwxrws--- 3 git git 27 7月 17 18:38 201109062119 +# drwxrws--- 3 git git 27 7月 17 18:38 chenxuanying +# drwxrws--- 6 git git 101 7月 17 18:38 crazyitman +# drwxrws--- 3 git git 27 7月 17 18:38 a5661390 +# drwxrws--- 8 git git 123 7月 17 18:38 cashewnut +# drwxrws--- 4 git git 52 7月 17 18:38 fuxinjiang +# drwxrwx--- 3 git git 27 7月 17 18:38 fuxiang +# drwxrws--- 3 git git 21 7月 17 18:38 gejian +# drwxrws--- 3 git git 27 7月 17 18:38 2013551712 +# drwxrws--- 3 git git 27 7月 17 18:38 gyy0104 +# drwxrwx--- 8 git git 129 7月 17 18:38 bufeibufei +# drwxrws--- 7 git git 122 7月 17 18:38 binling +# drwxrws--- 7 git git 132 7月 17 18:38 199395 +# drwxrws--- 3 git git 27 7月 17 18:38 berg +# drwxrws--- 4 git git 49 7月 17 18:38 201528016029011 +# drwxrws--- 5 git git 69 7月 17 18:38 caoyuan +# drwxrws--- 3 git git 27 7月 17 18:38 clavichord93 +# drwxrws--- 5 git git 71 7月 17 18:38 fansijiang +# drwxrws--- 4 git git 52 7月 17 18:38 chentong +# drwxrws--- 7 git git 91 7月 17 18:38 gaoyongzhan +# drwxrws--- 6 git git 85 7月 17 18:38 201509066020 +# drwxrws--- 6 git git 89 7月 17 18:38 aca16 +# drwxrws--- 5 git git 77 7月 17 18:38 deland99 +# drwxrws--- 3 git git 22 7月 17 18:38 doommerchant +# drwxrws--- 8 git git 157 7月 17 18:38 coder +# drwxrws--- 3 git git 27 7月 17 18:38 godwetrust +# drwxrws--- 3 git git 27 7月 17 18:38 gyang973256 +# drwxrws--- 4 git git 43 7月 17 18:38 caoshujin001 +# drwxrws--- 10 git git 205 7月 17 18:38 chensiyuan15 +# drwxrws--- 9 git git 134 7月 17 18:39 aqsxdefv +# drwxrws--- 3 git git 25 7月 17 18:39 darkuniverse +# drwxrws--- 4 git git 48 7月 17 18:39 201409062123 +# drwxrws--- 3 git git 27 7月 17 18:39 gwyneth1818 +# drwxrws--- 4 git git 48 7月 17 18:39 crazyyd +# drwxrws--- 3 git git 27 7月 17 18:39 2013551820 +# drwxrws--- 5 git git 69 7月 17 18:39 a111 +# drwxrws--- 3 git git 27 7月 17 18:39 950727 +# drwxrws--- 5 git git 73 7月 17 18:39 baohb +# drwxrws--- 7 git git 143 7月 17 18:39 caojiaxin +# drwxrws--- 3 git git 27 7月 17 18:39 1017 +# drwxrws--- 10 git git 174 7月 17 18:39 chenpeng15 +# drwxrws--- 6 git git 84 7月 17 18:39 damid +# drwxrws--- 3 git git 27 7月 17 18:39 big +# drwxrws--- 6 git git 101 7月 17 18:39 201528015029001 +# drwxrws--- 3 git git 27 7月 17 18:39 fyzhang +# drwxrws--- 3 git git 23 7月 17 18:39 547618026 +# drwxrws--- 14 git git 257 7月 17 18:39 demouser +# drwxrws--- 6 git git 84 7月 17 18:39 daguocai +# drwxrws--- 3 git git 25 7月 17 18:39 cxw931012 +# drwxrws--- 4 git git 66 7月 17 18:39 2013551823 +# drwxrws--- 3 git git 21 7月 17 18:39 fccccc +# drwxrws--- 8 git git 133 7月 17 18:39 chishuqi +# drwxrwx--- 3 git git 27 7月 17 18:39 csuzxa +# drwxrws--- 5 git git 87 7月 17 18:39 ghlozyx +# drwxrws--- 5 git git 73 7月 17 18:39 201618004133060 +# drwxrws--- 4 git git 51 7月 17 18:39 goujian +# drwxrws--- 7 git git 111 7月 17 18:39 code_monkey +# drwxrws--- 3 git git 27 7月 17 18:39 cuijingyong +# drwxrws--- 9 git git 139 7月 17 18:39 caochen +# drwxrws--- 3 git git 23 7月 17 18:39 bb411763600 +# drwxrws--- 6 git git 103 7月 17 18:39 cyberdb +# drwxrws--- 9 git git 159 7月 17 18:39 cookie +# drwxrws--- 7 git git 127 7月 17 18:39 chener +# drwxrws--- 3 git git 34 7月 17 18:39 ghostsys +# drwxrwx--- 3 git git 31 7月 17 18:39 1246299550 +# drwxrws--- 3 git git 25 7月 17 18:39 caicaiyan +# drwxrws--- 5 git git 78 7月 17 18:39 difanyi +# drwxrws--- 3 git git 27 7月 17 18:39 chilin +# drwxrws--- 4 git git 44 7月 17 18:39 fiona_w +# drwxrws--- 3 git git 27 7月 17 18:39 guwenkai +# drwxrws--- 3 git git 27 7月 17 18:39 guoziyang +# drwxrwx--- 3 git git 27 7月 17 18:39 gf457832386 +# drwxrws--- 5 git git 67 7月 17 18:39 dangzhiteng +# drwxrws--- 4 git git 48 7月 17 18:40 chenmengxiao +# drwxrws--- 8 git git 137 7月 17 18:40 dianer123 +# drwxrws--- 24 git git 4096 7月 17 18:40 guange +# drwxrws--- 8 git git 138 7月 17 18:40 fhx569287825 +# drwxrws--- 11 git git 210 7月 17 18:40 daiao +# drwxrws--- 6 git git 90 7月 17 18:40 changxuefeng +# drwxrws--- 3 git git 27 7月 17 18:40 ceaserz +# drwxrws--- 3 git git 27 7月 17 18:40 c0411034 +# drwxrws--- 6 git git 84 7月 17 18:40 asdypeij +# drwxrws--- 3 git git 25 7月 17 18:40 bin5220 +# drwxrws--- 4 git git 56 7月 17 18:40 brucexiajun +# drwxrws--- 3 git git 27 7月 17 18:40 emon +# drwxrws--- 10 git git 154 7月 17 18:40 chazhidao +# drwxrws--- 3 git git 27 7月 17 18:40 dengding +# drwxrwx--- 4 git git 49 7月 17 18:40 bufeibufeibufei +# drwxrws--- 3 git git 24 7月 17 18:40 dsy6 +# drwxrws--- 4 git git 52 7月 17 18:40 changxiaoning +# drwxrws--- 3 git git 27 7月 17 18:40 chenyanrong +# drwxrws--- 5 git git 64 7月 17 18:40 buaaxzl +# drwxrws--- 5 git git 68 7月 17 18:40 fuyou2017 +# drwxrws--- 12 git git 203 7月 17 18:40 baiyu +# drwxrws--- 6 git git 90 7月 17 18:40 1430297883 +# drwxrws--- 3 git git 27 7月 17 18:40 1771306659 +# drwxrws--- 3 git git 27 7月 17 18:40 binhai.feng +# drwxrwx--- 6 git git 96 7月 17 18:40 gtt301617 +# drwxrws--- 3 git git 24 7月 17 18:40 chentao12a +# drwxrws--- 6 git git 139 7月 17 18:40 duweijing +# drwxrws--- 3 git git 27 7月 17 18:40 1508090032 +# drwxrws--- 5 git git 72 7月 17 18:40 dvhfb +# drwxrws--- 70 git git 4096 7月 17 18:40 root +# drwxrws--- 4 git git 43 7月 17 18:40 aa411763600 +# drwxrws--- 6 git git 97 7月 17 18:40 chenmengwen +# drwxrws--- 3 git git 27 7月 17 18:40 danger +# drwxrws--- 14 git git 228 7月 17 18:41 bingningning21 +# drwxrws--- 13 git git 302 7月 17 18:41 gcm3651 +# drwxrws--- 3 git git 27 7月 17 18:41 fengyuansun +# drwxrws--- 10 git git 182 7月 17 18:41 173280609 +# drwxrws--- 29 git git 4096 7月 17 18:41 gyiang +# drwxrws--- 10 git git 173 7月 17 18:41 evak110 +# drwxrws--- 3 git git 27 7月 17 18:41 bjhit +# drwxrws--- 4 git git 52 7月 17 18:41 guowenli +# drwxrws--- 3 git git 27 7月 17 18:41 feivo +# drwxrws--- 4 git git 48 7月 17 18:41 gdfly +# drwxrws--- 5 git git 79 7月 17 18:41 2272437706 +# drwxrwx--- 5 git git 75 7月 17 18:41 aaloneisland +# drwxrws--- 8 git git 128 7月 17 18:41 ddddsd +# drwxrws--- 7 git git 100 7月 17 18:41 fanguangsheng +# drwxrws--- 9 git git 146 7月 17 18:41 chehuimin +# drwxrws--- 21 git git 4096 7月 17 18:41 forge01 +# drwxrws--- 3 git git 27 7月 17 18:42 almkaiser +# drwxrws--- 6 git git 106 7月 17 18:42 ghlozyx2016 +# drwxrws--- 3 git git 27 7月 17 18:42 baozidexieqiao +# drwxrws--- 4 git git 46 7月 17 18:42 eef +# drwxrws--- 14 git git 254 7月 17 18:42 gayeep +# drwxrws--- 7 git git 111 7月 17 18:42 chenhuifeng +# drwxrws--- 3 git git 29 7月 17 18:49 coosa0 +# drwxrwx--- 54 git git 4096 7月 17 18:49 a411763600 +# drwxrws--- 10 git git 184 7月 17 18:51 cxt +# drwxrwx--- 4 git git 70 7月 17 18:51 feng3 +# drwxrws--- 7 git git 109 7月 17 18:51 chensha +# drwxrwx--- 58 git git 4096 7月 18 16:50 wangtao +# drwxrwx--- 3 git git 26 7月 18 19:24 gulian +# drwxr-xr-x 13 git git 252 7月 20 14:15 sylorhuang +# drwxrws--- 5 git git 64 7月 20 16:24 lqchen +# drwxrwx--- 3 git git 28 7月 20 16:44 primenumber +# drwxrws--- 23 git git 4096 7月 21 11:23 jasder" + +# nn = "drwxrwx--- 2 git git 4096 4月 20 10:31 ljxin559 +# drwxrwx--- 2 git git 4096 4月 21 20:21 liumeixi +# drwxrwx--- 2 git git 4096 4月 22 09:52 jiangke +# drwxrwx--- 2 git git 4096 4月 22 14:30 tanyu +# drwxrwx--- 2 git git 4096 4月 22 14:31 mazhihui +# drwxrwx--- 2 git git 4096 4月 22 14:32 asmallsun +# drwxrwx--- 2 git git 4096 4月 22 14:33 cpr123 +# drwxrwx--- 2 git git 4096 4月 22 14:44 zlyy +# drwxrwx--- 2 git git 4096 4月 22 14:44 qdl2019112120 +# drwxrwx--- 2 git git 4096 4月 22 14:46 xtzslx +# drwxrwx--- 2 git git 4096 4月 22 14:48 zhangsiyu +# drwxrwx--- 2 git git 4096 4月 22 14:48 yourjuly +# drwxrwx--- 2 git git 4096 4月 22 14:51 benny +# drwxrwx--- 2 git git 4096 4月 22 14:51 blgwq +# drwxrwx--- 2 git git 4096 4月 22 14:54 xlszd +# drwxrwx--- 2 git git 4096 4月 22 15:00 liyuan929 +# drwxrwx--- 2 git git 4096 4月 22 15:01 kuangmx +# drwxrwx--- 2 git git 4096 4月 22 15:02 daijingyi +# drwxrwx--- 2 git git 4096 4月 22 15:03 LXQ098 +# drwxrwx--- 2 git git 4096 4月 22 15:04 mlhlzds +# drwxrwx--- 2 git git 4096 4月 22 15:30 Yesene +# drwxrwx--- 2 git git 4096 4月 22 16:17 Lauv.luziyi +# drwxrwx--- 2 git git 4096 4月 22 16:21 lyw2019112215 +# drwxrwx--- 2 git git 4096 4月 22 16:25 gxm2019112207 +# drwxrwx--- 2 git git 4096 4月 22 16:27 PuCC +# drwxrwx--- 2 git git 4096 4月 22 16:27 ty12 +# drwxrwx--- 2 git git 4096 4月 22 16:31 paradiseling +# drwxrwx--- 2 git git 4096 4月 22 16:32 sjy22 +# drwxrwx--- 2 git git 4096 4月 22 16:33 Surong +# drwxrwx--- 2 git git 4096 4月 22 17:00 Ch1017 +# drwxrwx--- 2 git git 4096 4月 22 17:08 ZQLIN +# drwxrwx--- 2 git git 4096 4月 22 17:08 lxylxy +# drwxrwx--- 2 git git 4096 4月 22 17:09 hzz010806 +# drwxrwx--- 2 git git 4096 4月 22 17:11 future1 +# drwxrwx--- 2 git git 4096 4月 22 17:13 flourish +# drwxrwx--- 2 git git 4096 4月 22 17:13 rainbow00 +# drwxrwx--- 2 git git 4096 4月 22 17:14 lxh11 +# drwxrwx--- 2 git git 4096 4月 22 17:18 orange0416 +# drwxrwx--- 2 git git 4096 4月 22 17:18 yanyan778 +# drwxrwx--- 2 git git 4096 4月 22 17:20 sweetheart +# drwxrwx--- 2 git git 4096 4月 22 18:03 Eliauk +# drwxrwx--- 2 git git 4096 4月 22 18:28 Homie +# drwxrwx--- 2 git git 4096 4月 22 18:38 chenyao333 +# drwxrwx--- 2 git git 4096 4月 22 18:39 zxy42 +# drwxrwx--- 2 git git 4096 4月 22 19:22 wsqq +# drwxrwx--- 2 git git 4096 4月 22 19:23 asdzxc +# drwxrwx--- 2 git git 4096 4月 22 19:36 apply +# drwxrwx--- 2 git git 4096 4月 22 19:48 Awin +# drwxrwx--- 2 git git 4096 4月 22 19:58 fangning +# drwxrwx--- 2 git git 4096 4月 22 20:10 Ther +# drwxrwx--- 2 git git 4096 4月 22 20:15 mrtber +# drwxrwx--- 2 git git 4096 4月 22 20:27 lijing7 +# drwxrwx--- 2 git git 4096 4月 22 20:28 zlp11 +# drwxrwx--- 2 git git 4096 4月 22 20:36 ky4209241005 +# drwxrwx--- 2 git git 4096 4月 22 20:57 DevilLi +# drwxrwx--- 2 git git 4096 4月 22 21:04 Jujubo +# drwxrwx--- 2 git git 4096 4月 22 21:07 dengjuan +# drwxrwx--- 2 git git 4096 4月 22 22:10 dandelionl +# drwxrwx--- 2 git git 4096 4月 22 22:49 zerorain +# drwxrwx--- 2 git git 4096 4月 23 01:38 a857 +# drwxrwx--- 2 git git 4096 4月 23 10:20 zy000 +# drwxrwx--- 2 git git 4096 4月 23 18:54 jyhhhh +# drwxrwx--- 2 git git 4096 4月 23 22:46 Azaurr +# drwxrwx--- 2 git git 4096 4月 24 14:02 Mical +# drwxrwx--- 2 git git 4096 4月 24 21:20 rowoon +# drwxrwx--- 2 git git 4096 4月 27 11:39 sjsj +# drwxrwx--- 2 git git 4096 4月 29 16:03 lu1712921837 +# drwxrwx--- 2 git git 4096 5月 7 16:15 anhriuiq +# drwxrws--- 25 git git 4096 5月 10 15:48 qiubing +# drwxrwx--- 2 git git 4096 5月 10 19:35 wyy100425 +# drwxrwx--- 2 git git 4096 5月 11 16:41 Karryk +# drwxrwx--- 2 git git 4096 5月 11 22:03 Sukifly +# drwxrwx--- 2 git git 4096 5月 11 22:19 shiluo +# drwxrwx--- 2 git git 4096 5月 11 22:52 Ethan4 +# drwxrwx--- 2 git git 4096 5月 11 22:57 enable +# drwxrwx--- 2 git git 4096 5月 12 10:51 songcheng123 +# drwxrwx--- 2 git git 4096 5月 12 12:01 doublecircle +# drwxrwx--- 2 git git 4096 5月 12 13:54 gaolongfei +# drwxrwx--- 2 git git 4096 5月 12 14:46 crystal0 +# drwxrws--- 20 git git 4096 5月 13 15:16 guange +# drwxrwx--- 2 git git 4096 5月 13 16:45 sxyzxd +# drwxrws--- 68 git git 4096 5月 14 11:10 root +# drwxrws--- 7 git git 4096 5月 15 08:54 net +# drwxrwx--- 2 git git 4096 5月 19 11:29 ma_shijuan +# drwxrwx--- 4 git git 4096 5月 20 10:57 hjl4am +# drwxrws--- 110 git git 4096 5月 20 11:08 Hjqreturn +# drwxrwx--- 3 git git 4096 5月 22 12:47 gtt301617 +# drwxrwx--- 2 git git 4096 5月 22 12:47 gujiaxiang +# drwxrwx--- 2 git git 4096 5月 22 12:47 woody13 +# drwxrwx--- 2 git git 4096 5月 22 12:47 Freshwinds +# drwxrwx--- 2 git git 4096 5月 22 12:47 atong97 +# drwxrwx--- 2 git git 4096 5月 22 12:47 AriesYao +# drwxrwx--- 2 git git 4096 5月 25 11:41 q527100546 +# drwxrws--- 4 git git 4096 5月 28 08:51 littlefinger +# drwxrws--- 9 git git 4096 5月 28 08:54 caochen +# drwxrws--- 4 git git 4096 5月 28 14:31 zhao2017 +# drwxrws--- 5 git git 4096 5月 29 10:41 kedai +# drwxrwx--- 2 git git 4096 5月 29 10:41 Arif +# drwxrwx--- 2 git git 4096 5月 29 10:41 Zhanglllfh +# drwxrws--- 6 git git 4096 5月 29 15:02 wrm1995 +# drwxrwx--- 2 git git 4096 5月 30 13:30 druks +# drwxrwx--- 2 git git 4096 5月 31 18:13 syw11806 +# drwxrws--- 5 git git 4096 6月 1 19:54 fangquntian +# drwxrwx--- 2 git git 4096 6月 2 11:43 zwk132613 +# drwxrwx--- 2 git git 4096 6月 3 09:44 panxiaosheng +# drwxrwx--- 2 git git 4096 6月 4 13:38 xiejianxiong +# drwxrwx--- 2 git git 4096 6月 5 14:00 yubaolun +# drwxrwx--- 2 git git 4096 6月 5 15:38 xinyao +# drwxrwx--- 2 git git 4096 6月 10 10:43 Racine +# drwxrwx--- 2 git git 4096 6月 10 19:58 VNJia +# drwxrwx--- 2 git git 4096 6月 13 11:26 Gany +# drwxrwx--- 2 git git 4096 6月 18 00:35 huojiajia +# drwxrwx--- 3 git git 4096 6月 20 23:39 FadePeople +# drwxrwx--- 12 git git 4096 6月 21 13:26 a411763600 +# drwxrws--- 8 git git 4096 6月 24 10:29 nudtpc +# drwxrwx--- 2 git git 4096 6月 24 10:29 zyq744 +# drwxrwx--- 2 git git 4096 6月 24 10:29 gf457832386 +# drwxrwx--- 2 git git 4096 6月 25 23:21 wslb +# drwxrwx--- 2 git git 4096 6月 27 11:42 a1s2d3 +# drwxrws--- 4 git git 4096 6月 27 16:45 Althur +# drwxrwx--- 2 git git 4096 6月 28 05:04 a151811 +# drwxrwx--- 2 git git 4096 7月 4 23:00 iwce +# drwxrwx--- 2 git git 4096 7月 7 13:37 a233 +# drwxrws--- 10 git git 4096 7月 7 16:28 SylorHuang +# drwxrwx--- 3 git git 4096 7月 9 14:30 wangliang +# drwxrwx--- 2 git git 4096 7月 9 14:30 MartinYuan +# drwxrwx--- 2 git git 4096 7月 9 14:30 alang +# drwxrwx--- 2 git git 4096 7月 9 15:57 MeMsc +# drwxrws--- 77 git git 4096 7月 10 09:11 starlee +# drwxrwx--- 2 git git 4096 7月 10 22:30 tmzg +# drwxrws--- 4 git git 4096 7月 11 02:23 zmiracle +# drwxrwx--- 3 git git 4096 7月 12 10:31 aaloneisland +# drwxrwx--- 2 git git 4096 7月 13 11:13 yuwei2005 +# drwxrws--- 10 git git 4096 7月 13 17:41 hushasha +# drwxrwx--- 2 git git 4096 7月 13 17:41 Royiwen +# drwxrwx--- 2 git git 4096 7月 13 17:41 liudong +# drwxrwx--- 2 git git 4096 7月 13 17:41 luliliang +# drwxrwx--- 2 git git 4096 7月 13 17:41 LDOU +# drwxrwx--- 2 git git 4096 7月 13 17:41 LoveSeed +# drwxrwx--- 2 git git 4096 7月 13 17:41 yangxiong +# drwxrwx--- 2 git git 4096 7月 17 10:37 luosuo10 +# drwxrwx--- 2 git git 4096 7月 17 14:28 yuxianger +# drwxrwx--- 2 git git 4096 7月 18 09:44 luoshaoshuai +# drwxrwx--- 2 git git 4096 7月 18 09:46 wl17862708856 +# drwxrwx--- 2 git git 4096 7月 18 09:48 JSYNWY +# drwxrwx--- 2 git git 4096 7月 18 09:48 fzp01 +# drwxrwx--- 2 git git 4096 7月 18 09:53 mumuou +# drwxrwx--- 2 git git 4096 7月 18 09:58 guojiabao +# drwxrwx--- 2 git git 4096 7月 18 09:58 swcstudy +# drwxrwx--- 2 git git 4096 7月 18 10:01 zhanglong4567 +# drwxrwx--- 2 git git 4096 7月 18 10:01 lipeng15 +# drwxrwx--- 2 git git 4096 7月 18 10:10 lixiong19 +# drwxrwx--- 2 git git 4096 7月 18 10:11 hhhh849 +# drwxrwx--- 2 git git 4096 7月 18 10:14 zhazha +# drwxrwx--- 2 git git 4096 7月 18 10:16 lizhenyi08 +# drwxrwx--- 2 git git 4096 7月 18 10:57 guorunze14 +# drwxrwx--- 2 git git 4096 7月 20 10:40 JavaClass +# drwxrwx--- 4 git git 4096 7月 20 10:47 ALPNAP" + +# m_array = nn.split("\n") +# n_array = [] +# m_array.each do |a| +# s = a.split(" ").last +# puts s+"," +# end + +# puts n_array.to_s \ No newline at end of file diff --git a/deploy.md b/deploy.md new file mode 100644 index 00000000..3eebaace --- /dev/null +++ b/deploy.md @@ -0,0 +1,95 @@ + +# 本地开发部署 + +## Depends Versions + +* Ruby 2.4.5 + +* Rails ~> 5.2 + +* MySql ~> 5.6 + +* Redis 5+ + + +## Steps + +### 1. 安装依赖包 + +```bash +bundle install +``` + +### 2. 配置初始化文件 +进入项目根目录执行一下命令: + +```bash +cp config/configuration.yml.example config/configuration.yml +cp config/database.yml.example config/database.yml +touch config/redis.yml +touch config/elasticsearch.yml +``` + +### 3. 配置gitea服务(可选) +**如需要部署自己的gitea平台,请参考gitea官方平台:https://docs.gitea.io/zh-cn/install-from-binary/** + +**因目前gitea平台api受限,暂时推荐从forge平台获取gitea部署文件进行部署:https://forgeplus.trustie.net/projects/6070/coders** + +#### 配置gitea服务步骤 +1. 部署gitea服务,并注册root账户 +2. 修改forge平台的 config/configuration.yml中的gitea服务指向地址,如: + +```ruby +gitea: + access_key_id: 'root' + access_key_secret: 'password' + domain: 'http://www.gitea.example.com' + base_url: '/api/v1' +``` + +### 4. 安装redis环境 +**请自行搜索各平台如何安装部署redis环境** + + +### 5. 创建数据库 + +```bash +rails db:create +``` + +### 6. 导入数据表结构 + +```bash +bundle exec rake sync_table_structure:import_csv +``` + +### 7. 执行migrate迁移文件 +**开发环境为development, 生成环境为production** +```bash +rails db:migrate RAILS_ENV=development +``` + +### 8. 启动redis(此处已mac系统为例) +```bash +redis-server& +``` + +### 9. 启动sidekiq +**开发环境为development, 生成环境为production** +```bash +bundle exec sidekiq -C config/sidekiq.yml -e production -d +``` + +### 10. 启动rails服务 +```bash +rails s +``` + +### 11. 浏览器访问 +在浏览器中输入如下地址访问: +```bash +http://localhost:3000/ +``` + + +--- diff --git a/deployment.md b/deployment.md new file mode 100644 index 00000000..e8e510f3 --- /dev/null +++ b/deployment.md @@ -0,0 +1,2004 @@ + +# 本地开发部署步骤 + +#### 1. 安装依赖包 + +```bash +bundle install +``` + +#### 2. 配置初始化文件 +进入项目根目录执行一下命令: + +```bash +cp config/configuration.yml.example config/configuration.yml +cp config/database.yml.example config/database.yml +touch config/redis.yml +touch config/elasticsearch.yml +``` + +#### 3. 创建数据库 + +```bash +rails db:create +``` + +#### 4. 导入数据表结构 + +```bash +bundle exec rake sync_table_structure:import_csv +``` + +#### 5. 执行migrate迁移文件 +```bash +rails db:migrate RAILS_ENV=development +``` + +#### 6. 启动rails服务 +```bash +rails s +``` + +#### 7. 浏览器访问 +在浏览器中输入如下地址访问: +```bash +http://localhost:3000/projects +``` + +--- + + +# API文档 + +## 基本介绍 + +开发API服务地址: + +https://testgitea.trustie.net/ + + +响应状态说明: + +|字段|类型|说明| +|-|-|-| +|status |int |响应状态码,0:请求成功,-1: 请求失败| +|message |string |响应说明 | + + +### API接口 +--- + +#### 用户注册(通过其他平台) +``` +POST accounts/remote_register +``` +*示例* +``` +curl -X POST \ +-d "email=2456233122@qq.com" \ +-d "password=djs_D_00001" \ +-d "username=16895620" \ +-d "platform=forge" \ +http://localhost:3000/api/accounts/remote_register | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|email |是|string |邮箱 | +|username |是|string |登录名 | +|password |是|string |秘密 | +|platform |否|string |用户来源的相关平台,取值范围['educoder', 'trustie', 'forge'], 默认值为forge | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|user|json object |返回数据| +|-- id |int |用户id | +|-- token |string|用户token| + + +返回值 +``` +{ + "status": 0, + "message": "success", + "user": { + "id": 36400, + "token": "8c87a80d9cfacc92fcb2451845104f35119eda96" + } +} +``` +--- + +#### 获取当前登录用户信息 +``` +GET api/users/me +``` +*示例* +``` +curl -X GET http://localhost:3000/api/users/me | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|user_id |int |用户id | +|username |string|用户名称| +|admin |boolean|是否为管理用户| +|login |string|登录名| +|image_url |string|用户头像| + + +返回值 +``` +{ + "username": "18816895620", + "login": "18816895620", + "user_id": 36401, + "image_url": "avatars/User/b", + "admin": false +} +``` +--- + +#### 用户列表(带搜索功能) +``` +GET api/users/list +``` +*示例* +``` +curl -X GET \ +-d "limit=10" \ +-d "search=18816895620" +http://localhost:3000/api/users/list | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|page |否|int |页数,第几页 | +|limit |否|int |每页多少条数据,默认15条 | +|search |否|string |用户名、登录名匹配搜索 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int |总用户条数 | +|users |array| | +|-- username |string|用户全名| +|-- login |string|用户登录名| +|-- user_id |int|用户id| +|-- image_url |string|用户头像| + +返回值 +``` +{ + "total_count": 1, + "users": [ + { + "username": "18816895620", + "login": "18816895620", + "user_id": 36401, + "image_url": "avatars/User/b" + } + ] +} +``` +--- + +#### 获取项目类别列表(可根据名称搜素) +``` +GET api/project_categories +``` +*示例* +``` +curl -X GET \ +-d "name=大数据" \ +http://localhost:3000/api/project_categories/ | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|name |否|string |类别名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|project_categories|array |返回数据| +|-- id |int |类别id | +|-- name |string|类别名称| + + +返回值 +``` +{ + "project_categories": [ + { + "id": 1, + "name": "大数据" + } + ] +} +``` +--- + +#### 获取项目语言列表(可根据名称搜素) +``` +GET api/project_languages +``` +*示例* +``` +curl -X GET \ +-d "name=Ruby" \ +http://localhost:3000/api/project_languages/ | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|name |否|string |类别名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|project_languages|array |返回数据| +|-- id |int |语言id | +|-- name |string|语言名称| + + +返回值 +``` +{ + "project_languages": [ + { + "id": 1, + "name": "Ruby" + } + ] +} +``` +--- + +#### 获取.gitignore模板列表(可根据名称搜素) +``` +GET api/ignores +``` +*示例* +``` +curl -X GET \ +-d "name=Ada" \ +http://localhost:3000/api/ignores/ | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|name |否|string |gitignore名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|ignores|array |返回数据| +|-- id |int |id | +|-- name |string|gitignore名称| + + +返回值 +``` +{ + "ignores": [ + { + "id": 1, + "name": "Ada" + } + ] +} +``` +--- + +#### 获取开源许可证列表(可根据名称搜素) +``` +GET api/licenses +``` +*示例* +``` +curl -X GET \ +-d "name=AFL" \ +http://localhost:3000/api/licenses/ | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|name |否|string |开源许可证名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|licenses|array |返回数据| +|-- id |int |id | +|-- name |string|开源许可证名称| + + +返回值 +``` +{ + "licenses": [ + { + "id": 57, + "name": "AFL-1.2" + }, + { + "id": 76, + "name": "AFL-3.0" + }, + { + "id": 214, + "name": "AFL-1.1" + }, + { + "id": 326, + "name": "AFL-2.1" + }, + { + "id": 350, + "name": "AFL-2.0" + } + ] +} +``` +--- + +#### 创建项目 +``` +POST api/projects +``` +*示例* +``` +curl -X POST \ +-d "user_id=36401" \ +-d "name=hnfl_demo" \ +-d "description=my first project" \ +-d "repository_name=hnfl_demo" \ +-d "project_category_id=1" \ +-d "project_language_id=2" \ +-d "ignore_id=2" \ +-d "license_id=1" \ +http://localhost:3000/api/projects/ | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|user_id |是|int |用户id或者组织id | +|name |是|string |项目名称 | +|description |是|string |项目描述 | +|repository_name |是|string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 | +|project_category_id|是|int |项目类别id | +|project_language_id|是|int |项目语言id | +|ignore_id |否|int |gitignore相关id | +|license_id |否|int |开源许可证id | +|private |否|boolean|项目是否私有, true:为私有,false: 公开,默认为公开 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |id | +|name |string|项目名称| + + +返回值 +``` +{ + "id": 3240, + "name": "好项目" +} +``` +--- + +#### 新建镜像项目 +``` +POST api/projects/migrate +``` +*示例* +``` +curl -X POST \ +-d "user_id=36401" \ +-d "clone_addr=https://gitea.com/mx8090alex/golden.git" \ +-d "name=golden" \ +-d "description=golden" \ +-d "repository_name=golden" \ +-d "project_category_id=1" \ +-d "project_language_id=2" \ +http://localhost:3000/api/projects/migrate | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|user_id |是|int |用户id或者组织id | +|name |是|string |项目名称 | +|clone_addr |是|string |镜像项目clone地址 | +|description |否|string |项目描述 | +|repository_name |是|string |仓库名称, 只含有数字、字母、下划线不能以下划线开头和结尾,且唯一 | +|project_category_id|是|int |项目类别id | +|project_language_id|是|int |项目语言id | +|private |否|boolean|项目是否私有, true:为私有,false: 非私有,默认为公开 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |id | +|name |string|项目名称| + + +返回值 +``` +{ + "id": 3263, + "name": "ni项目" +} +``` +--- + +#### 项目详情 +``` +GET api/projects/:id +``` +*示例* +``` +curl -X GET http://localhost:3000/api/projects/3263 | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |id | +|name |string|项目名称| +|identifier |string|项目标识| +|is_public |boolean|项目是否公开, true:公开,false:私有| +|description |string|项目简介| +|repo_id |int|仓库id| +|repo_identifier|string|仓库标识| + + +返回值 +``` +{ + "name": "ni项目", + "identifier": "mirror_demo", + "is_public": true, + "description": "my first project mirror_demo", + "repo_id": 75073, + "repo_identifier": "mirror_demo" +} +``` +--- + +#### 编辑仓库信息 +``` +GET /api/:login/:repo_identifier/edit.json +``` +*示例* +``` +curl -X GET http://localhost:3000/api/18816895620/mirror_demo/edit.json | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|identifier |string |仓库标识 | +|project_id |int|项目id| +|project_name |string|项目名称| +|project_identifier |string|项目标识| +|project_description |string|项目简介| +|project_category_id |int|项目类别id| +|project_language_id |int|项目语言id| +|private |boolean|项目是否私有, true:为私有,false: 公开 | + + +返回值 +``` +{ + "identifier": "mirror_demo", + "project_id": 3263, + "project_name": "ni项目", + "project_identifier": "mirror_demo", + "project_description": "my first project mirror_demo", + "project_category_id": 1, + "project_language_id": 2, + "private": false +} +``` +--- + +#### 修改项目信息 +``` +PATCH api/projects/:id +``` +*示例* +``` +curl -X PATCH \ +-d "name=hnfl_demo" \ +-d "description=my first project" \ +-d "project_category_id=1" \ +-d "project_language_id=2" \ +-d "private=true" \ +http://localhost:3000/api/projects/3263.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|name |否|string |项目名称 | +|description |否|string |项目描述 | +|project_category_id|否|int |项目类别id | +|project_language_id|否|int |项目语言id | +|private |否|boolean|项目是否私有, true:为私有,false: 公开,默认为公开 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int|id | +|identifier |string|项目标识| +|name |string|项目名称| +|description |string|项目简介| +|project_category_id|int|项目类别id| +|project_language_id|int|项目语言id| +|private |否|boolean|项目是否私有, true:为私有,false: 公开,默认为公开 | + + +返回值 +``` +{ + "id": 3263, + "identifier": "mirror_demo", + "name": "hnfl_demo", + "description": "my first project", + "project_category_id": 1, + "project_language_id": 2, + "is_public": true +} +``` +--- + +#### 删除项目 +``` +DELETE api/projects/:id +``` +*示例* +``` +curl -X DELETE http://localhost:3000/api/projects/3263.json | jq +``` + +注:只有超级管理员和项目拥有者才能删除仓库 + +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|返回状态, 0: 表示操作成功 | +|message |string|返回信息说明| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +#### 项目添加成员 +``` +POST api/projects/:id/members +``` +*示例* +``` +curl -X POST \ +-d "user_id=36406" \ +http://localhost:3000/api/projects/3297/members | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|user_id |是|int |用户id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int |0:添加成功, -1: 添加失败, 1: 表示已经是项目成员 | +|message |string|返回信息说明| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +#### 项目删除成员 +``` +DELETE api/projects/:id/members/remove +``` +*示例* +``` +curl -X DELETE \ +-d "user_id=36400" \ +http://localhost:3000/api/projects/3263/members/remove | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|user_id |是|int |用户id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int |0:移除成功, -1: 移除失败, 1: 表示还不是项目成员 | +|message |string|返回信息说明| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +#### 更改项目成员角色/权限 +``` +PUT api/projects/:id/members/change_role +``` +*示例* +``` +curl -X PUT \ +-d "user_id=36400" \ +-d "role=Developer" \ +http://localhost:3000/api/projects/3263/members/change_role | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|user_id |是|int |用户id | +|role |是|string |取值范围:"Manager", "Developer", "Reporter";分别为项目管理人员(拥有所有操作权限)、项目开发人员(只拥有读写权限)、项目报告人员(只拥有读权限) | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int |0:角色更改成功, -1: 更改失败失败, 1: 表示还不是项目成员 | +|message |string|返回信息说明| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + + +#### 项目成员列表 +``` +GET api/projects/:id/members +``` +*示例* +``` +curl -X GET \ +-d "page=1" \ +-d "limit=5" \ +http://localhost:3000/api/projects/3263/members | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|page |否|string |页数,第几页 | +|limit |否|string |每页多少条数据,默认15条 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int |返回记录总条数 | +|members |array|项目成员信息| +|-- id |int|用户id| +|-- name |string|用户名称| +|-- login |string|用户登录名/标识| +|-- image_url |string|用户头像| +|-- is_owner |boolean|是否是项目的拥有者,true:是, false:不是| +|-- role |string|该用户在项目中的角色, Manager: 管理员(拥有操作权限); Developer:开发人员(只拥有读写权限); Reporter:报告人员(只拥有读权限)| + + +返回值 +``` +{ + "total_count": 2, + "members": [ + { + "id": 36401, + "name": "18816895620", + "login": "18816895620", + "image_url": "avatars/User/b", + "is_owner": true, + "role": "Manager" + }, + { + "id": 36399, + "name": "18816365620", + "login": "18816365620", + "image_url": "avatars/User/b", + "is_owner": false, + "role": "Developer" + } + ] +} +``` +--- + +#### Fork项目 +``` +POST /api/projects/:project_id/forks +``` +*示例* +``` +curl -X POST http://localhost:3000/api/projects/3297/forks | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|project_id |是|int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |项目id | +|identifier |string|项目标识| + + +返回值 +``` +{ + "id": 3290, + "identifier": "newadm" +} +``` +--- + +#### 获取代码目录列表 +``` +POST api/:login/:repo_identifier/entries +``` +*示例* +``` +curl -X GET \ +-d "ref=develop" \ +http://localhost:3000/api/18816895620/mirror_demo/entries | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|ref |否|string |分支名称、tag名称或是提交记录id,默认为master分支 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |id | +|name |string|文件夹或文件名称| +|path |string|文件夹或文件相对路径| +|type |string|文件类型, file:文件,dir:文件目录| +|size |int|文件夹或文件大小 单位B| +|content |string|文件内容,| +|target |string|标签| + +返回值 +``` +[ + { + "name": "Manual", + "path": "Manual", + "sha": "c2f18765235076b4c835b3e31262b3ee65176a75", + "type": "file", + "size": 12579, + "content": null, + "target": null, + "commit": null + }, + { + "name": "README", + "path": "README", + "sha": "91a29176828eba5c5598f5d4a95458e861f271ec", + "type": "file", + "size": 1767, + "content": null, + "target": null, + "commit": null + }, + { + "name": "base", + "path": "base", + "sha": "7adbe5698e02dba062216333d5e1d16b36ae1cbd", + "type": "dir", + "size": 0, + "content": null, + "target": null, + "commit": null + } +] +``` +--- + +#### 获取子目录代码列表/编辑某个具体的文件 +``` +GET api/:login/:repo_identifier/sub_entries +``` +*示例* +``` +curl -X GET \ +-d "ref=master" \ +-d "filepath=test1_create_file.rb" \ +http://localhost:3000/api/18816895620/mirror_demo/sub_entries | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|filepath |是|string |文件夹、文件的相对路径 | +|ref |否|string |分支名称、tag名称或是提交记录id,默认为master分支 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |id | +|name |string|文件夹或文件名称| +|path |string|文件夹或文件相对路径| +|type |string|文件类型, file:文件,dir:文件目录| +|size |int|文件夹或文件大小 单位KB| +|content |string|文件内容,| +|target |string|标签| +|url |string|文件访问链接,带分支| +|html_url |string|文件访问链接,未标识分支| +|git_url |string|文件夹或文件的git仓库访问链接| +|download_url |string|文件下载、文件内容访问链接| + +返回值 +``` +[ + { + "name": "build.rc", + "path": "lib/build.rc", + "type": "", + "size": 1268, + "content": null, + "target": null, + "url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/contents/lib/build.rc?ref=master", + "html_url": "http://localhost:3003/18816895620/mirror_demo/src/branch/master/lib/build.rc", + "git_url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/git/blobs/191fcf1a63b3777e2977fcede7dd5309efdd70fe", + "download_url": null + }, + { + "name": "cfg.rc", + "path": "lib/cfg.rc", + "type": "file", + "size": 107, + "content": null, + "target": null, + "url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/contents/lib/cfg.rc?ref=master", + "html_url": "http://localhost:3003/18816895620/mirror_demo/src/branch/master/lib/cfg.rc", + "git_url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/git/blobs/0b91ba0ed1c00e130c77bb9058af3787fea986a0", + "download_url": "http://localhost:3003/18816895620/mirror_demo/raw/branch/master/lib/cfg.rc" + }, + { + "name": "fn", + "path": "lib/fn", + "type": "dir", + "size": 0, + "content": null, + "target": null, + "url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/contents/lib/fn?ref=master", + "html_url": "http://localhost:3003/18816895620/mirror_demo/src/branch/master/lib/fn", + "git_url": "http://localhost:3003/api/v1/repos/18816895620/mirror_demo/git/blobs/e33bd45949ef8f804471d0b6b2c59728eb445989", + "download_url": null + } +] +``` +--- + +#### 项目类别列表(用于项目列表左侧导航中的项目类别列表) +``` +GET api/project_categories/group_list +``` +*示例* +``` +curl -X GET http://localhost:3000/api/project_categories/group_list | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|id |int |项目分类id | +|name |string|项目分类名称| +|projects_count |int |项目数量| + + +返回值 +``` +[ + { + "id": 1, + "name": "大数据", + "projects_count": 30 + }, + { + "id": 2, + "name": "机器学习", + "projects_count": 1 + }, + { + "id": 3, + "name": "深度学习", + "projects_count": 1 + } +] +``` +--- + +#### 项目类型列表(用于项目列表左侧导航上方中的项目类型列表) +``` +GET api/projects/group_type_list +``` +*示例* +``` +curl -X GET http://localhost:3000/api/projects/group_type_list | jq +``` + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|project_type |string|项目类型 | +|name |string|项目类型名称| +|projects_count |int |项目数量| + + +返回值 +``` +[ + { + "project_type": "common", + "name": "开源托管项目", + "projects_count": 2106 + }, + { + "project_type": "mirror", + "name": "开源镜像项目", + "projects_count": 1 + } +] +``` +--- + +#### 项目列表 +``` +GET api/projects +``` +*示例* +``` +curl -X GET \ +-d "page=1" \ +-d "limit=5" \ +http://localhost:3000/api/projects | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|page |否|string |页数,第几页 | +|limit |否|string |每页多少条数据,默认15条 | +|sort_by |否|string |排序类型, 取值:updated_on \| created_on \| forked_count \| praises_count, updated_on: 更新时间排序,created_on: 创建时间排序,forked_count: fork数据排序,praises_count: 点赞数量排序,默认为updated_on更新时间排序 | +|sort_direction|否|string |排序方式,取值为: desc \| asc; desc: 降序排序, asc: 升序排序, 默认为:desc | +|search |否|string |按照项目名称搜索 | +|category_id |否|int |项目类别id | +|language_id |否|int |项目语言id | +|project_type |否|string |项目类型, 取值为:common \| mirror; common:开源托管项目, mirror:开源镜像项目 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int |项目总条数 | +|id |string |项目id | +|name |string|项目名称| +|description |string|项目简介| +|visits |int|流量数| +|forked_count |int|被fork的数量| +|praises_count |int|star数量| +|is_public |boolean|是否公开, true:公开,false:未公开| +|mirror_url |string|镜像url| +|last_update_time|int|最后更新时间,为UNIX格式的时间戳| +|author |object|项目创建者| +|-- name |string|用户名,也是用户标识| +|category |object|项目类别| +|-- id |int|项目类型id| +|-- name |string|项目类型名称| +|language |object|项目语言| +|-- id |int|项目语言id| +|-- name |string|项目语言名称| + + +返回值 +``` +{ + "total_count": 3096, + "projects": [ + { + "id": 1, + "name": "hnfl_demo1", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": null, + "last_update_time": 1577697461, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + }, + { + "id": 2, + "name": "hnfl_demo", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": null, + "last_update_time": 1577697403, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + }, + { + "id": 3, + "name": "统计局", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": null, + "last_update_time": 1577415173, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + }, + { + "id": 5, + "name": "开源同名", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": false, + "mirror_url": "https://gitea.com/CasperVector/slew.git", + "last_update_time": 1577346228, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + }, + { + "id": 7, + "name": "开源支持", + "description": "my first project", + "visits": 0, + "praises_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": null, + "last_update_time": 1577341572, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + }, + "category": { + "id": 1, + "name": "大数据" + }, + "language": { + "id": 2, + "name": "C" + } + } + ] +} +``` +--- + +### 获取分支列表 +``` +GET /api/projects/:identifier/branches +``` +*示例* +``` +curl -X GET http://localhost:3000/api/projects/mirror_demo/branches | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|identifier |是|string |项目标识 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|name |string|分支名称| +|user_can_push |boolean|用户是否可push| +|user_can_merge |boolean|用户是否客merge| +|protected |boolean|是否为保护分支| +|http_url |boolean|http链接| +|zip_url |boolean|zip包下载链接| +|tar_url |boolean|tar.gz下载链接| +|last_commit |object|最后提交记录| +|-- id |string|提交记录id| +|-- message |string|提交的说明信息| +|-- timestamp |int|提交时间,为UNIX时间戳| +|-- time_from_now|string|转换后的时间| +|author |object|提交用户| +|-- login |string|用户名称| +|-- image_url |string|用户头像| + + +返回值 +``` +[ + { + "name": "develop", + "user_can_push": true, + "user_can_merge": true, + "protected": false, + "http_url": "http://localhost:3003/18816895620/mirror_demo.git", + "zip_url": "http://localhost:3003/18816895620/mirror_demo/develop.zip", + "tar_url": "http://localhost:3003/18816895620/mirror_demo/develop.tar.gz", + "last_commit": { + "id": "735674d6696bddbafa993db9c67b40c41246c77f", + "message": "FIX test branch content\n", + "timestamp": 1577694074, + "time_from_now": "1天前" + }, + "author": { + "login": "18816895620", + "image_url": "avatars/User/b" + } + }, + { + "name": "master", + "user_can_push": true, + "user_can_merge": true, + "protected": false, + "http_url": "http://localhost:3003/18816895620/mirror_demo.git", + "zip_url": "http://localhost:3003/18816895620/mirror_demo/master.zip", + "tar_url": "http://localhost:3003/18816895620/mirror_demo/master.tar.gz", + "last_commit": { + "id": "19ac3bc45f62cc87a94b8ecce61101d8fd2dafd2", + "message": "合并pull request测试\n\n该功能很不错,感谢你的建议\n", + "timestamp": 1577244567, + "time_from_now": "6天前" + }, + "author": { + "login": "18816895620", + "image_url": "avatars/User/b" + } + } +] +``` +--- + +### 获取版本列表 +``` +GET /api/:login/:repo_identifier/tags +``` +*示例* +``` +curl -X GET http://localhost:3000/api/18816895620/mirror_demo/tags | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +-|-|- +|name |string|分支名称| +|user_can_push |boolean|用户是否可push| +|user_can_merge |boolean|用户是否客merge| +|protected |boolean|是否为保护分支| +|http_url |boolean|http链接| +|zip_url |boolean|zip包下载链接| +|tar_url |boolean|tar.gz下载链接| +|last_commit |object|最后提交记录| +|-- id |string|提交记录id| +|-- message |string|提交的说明信息| +|-- timestamp |int|提交时间,为UNIX时间戳| +|-- time_from_now|string|转换后的时间| +|author |object|提交用户| +|-- login |string|用户名称| +|-- image_url |string|用户头像| + + +返回值 +``` +[ + { + "name": "develop", + "user_can_push": true, + "user_can_merge": true, + "protected": false, + "http_url": "http://localhost:3003/18816895620/mirror_demo.git", + "zip_url": "http://localhost:3003/18816895620/mirror_demo/develop.zip", + "tar_url": "http://localhost:3003/18816895620/mirror_demo/develop.tar.gz", + "last_commit": { + "id": "735674d6696bddbafa993db9c67b40c41246c77f", + "message": "FIX test branch content\n", + "timestamp": 1577694074, + "time_from_now": "1天前" + }, + "author": { + "login": "18816895620", + "image_url": "avatars/User/b" + } + }, + { + "name": "master", + "user_can_push": true, + "user_can_merge": true, + "protected": false, + "http_url": "http://localhost:3003/18816895620/mirror_demo.git", + "zip_url": "http://localhost:3003/18816895620/mirror_demo/master.zip", + "tar_url": "http://localhost:3003/18816895620/mirror_demo/master.tar.gz", + "last_commit": { + "id": "19ac3bc45f62cc87a94b8ecce61101d8fd2dafd2", + "message": "合并pull request测试\n\n该功能很不错,感谢你的建议\n", + "timestamp": 1577244567, + "time_from_now": "6天前" + }, + "author": { + "login": "18816895620", + "image_url": "avatars/User/b" + } + } +] +``` +--- + +## 仓库详情 +``` +GET /api/:login/:repo_identifier/ +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/18816895620/mirror_demo | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|string |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|identifier |string|仓库标识| +|project_id |int|项目id| +|project_identifier|string|项目标识| +|praises_count |int|点赞数量| +|forked_count |int|fork数量| +|watchers_count |int|关注数量| +|branches_count |int|分支数量| +|commits_count |int|总提交记录数量| +|issues_count |int|总提交记录数量| +|pull_requests_count |int|总提交记录数量| +|praised |boolean|当前登录用户是否已点赞,true:已点赞,fasle:未点赞, 用户未登录状态为null| +|watched |boolean|当前登录用户是否已关注,true:已关注,fasle:未关注, 用户未登录状态为null| +|permission |string|当前登录用户对该仓库的操作权限, Manager:管理员,可以在线编辑文件、在线新建文件、可以设置仓库的基本信息; Developer:开发人员,可在线编辑文件、在线新建文件、不能设置仓库信息; Reporter: 报告人员,只能查看信息,不能设置仓库信息、不能在线编辑文件、不能在线新建文件;用户未登录时也会返回Reporter, 说明也只有读取文件的权限 | +|size |int|仓库文件大小,单位:KB| +|mirror_url |string|镜像地址, 只有通过镜像过来的项目才会有这个地址| +|ssh_url |string|仓库ssh地址| +|clone_url |string|仓库克隆地址| +|empty |boolean|仓库是否为空,true: 空仓库;false: 非空仓库| +|private |boolean|仓库是否私有,true: 私有仓库;fasle: 非私有的| +|default_branch |string|仓库默认分支| +|full_name |string|仓库全名(带用户名)| +|author |object|提交用户| +|-- login |string|用户login| +|-- name |string|用户姓名| +|-- image_url |string|用户头像| + + +返回值 +``` +{ + "identifier": "mirror_demo", + "project_id": 3263, + "project_identifier": "mirror_demo", + "praises_count": 1, + "forked_count": 0, + "watchers_count": 1, + "branches_count": 6, + "commits_count": 107, + "issues_count": 0, + "pull_requests_count": 0, + "permission": "Manager", + "mirror_url": "https://gitea.com/CasperVector/slew.git", + "watched": true, + "praised": true, + "size": 446, + "ssh_url": "jasder@localhost:18816895620/mirror_demo.git", + "clone_url": "http://localhost:3003/18816895620/mirror_demo.git", + "default_branch": "master", + "empty": false, + "full_name": "18816895620/mirror_demo", + "mirror": false, + "private": false, + "author": { + "login": "18816895620", + "name": "美女", + "image_url": "avatars/User/b" + } +} +``` +--- + +## 获取提交记录列表 +``` +GET /api/:login/:repo_identifier/commits +``` +*示例* +``` +curl -X GET \ +-d "sha=develop" \ +-d "page=1" \ +http://localhost:3000/api/18816895620/mirror_demo/commits | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|sha |否|string |分支名称、提交记录的sha标识,默认为master分支 | +|page |否|int |页数, 默认为1 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count|int|总记录条数| +|commits |array|提交记录的数组| +|-- sha |string|提交记录sha标识| +|-- message |string|提交的备注说明| +|-- timestamp |int|提交UNIX时间戳| +|-- time_from_now|string|提交距离当前的时间| +|author |object|提交用户| +|-- login |string|用户名称| +|-- image_url |string|用户头像| + + +返回值 +``` +{ + "total_count": 63, + "commits": [ + { + "sha": "19ac3bc45f62cc87a94b8ecce61101d8fd2dafd2", + "message": "合并pull request测试", + "timestamp": 1577244567, + "time_from_now": "7天前", + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + } + }, + { + "sha": "2b33c5f55214db41879936312ee43611406c4dbd", + "message": "FIX .", + "timestamp": 1577244474, + "time_from_now": "7天前", + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + } + } + ] +} +``` +--- + +### 点赞 +``` +POST /api/projects/:id/praise_tread/like +``` +*示例* +``` +curl -X POST http://localhost:3000/api/projects/3263/praise_tread/like | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是 |int |项目id | + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:点赞成功,-1:操作失败,2:表示已经点过赞了| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +### 取消点赞 +``` +DELETE /api/projects/:id/praise_tread/unlike +``` +*示例* +``` +curl -X DELETE http://localhost:3000/api/projects/3263/praise_tread/unlike | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是 |int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:点赞成功,-1:操作失败,2:表示还未点赞| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +### 用户是否点过赞 +``` +GET /api/projects/:id/praise_tread/check_like +``` +*示例* +``` +curl -X GET http://localhost:3000/api/projects/3263/praise_tread/check_like | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是 |int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|1:已点过赞,0:未点过赞, -1:请求操作失败| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +### 项目的点赞者列表 +``` +GET /api/projects/:id/praise_tread +``` +*示例* +``` +curl -X GET \ +-d "page=1" \ +-d "limit=5" \ +http://localhost:3000/api/projects/3263/praise_tread | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|page |否|string |页数,第几页 | +|limit |否|string |每页多少条数据,默认15条 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int|总条数| +|praises |array|点赞数据| +|-- name |string|用户名称| +|-- login |string|用户标识/登录名(login)| +|-- image_url |string|用户头像| + + + +返回值 +``` +{ + "total_count": 1, + "praises": [ + { + "name": "18816895620", + "login": "18816895620", + "image_url": "avatars/User/b" + } + ] +} +``` +--- + +### 关注(项目) +``` +POST /api/projects/:id/watchers/follow +``` +*示例* +``` +curl -X POST http://localhost:3000/api/projects/3263/watchers/follow | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:点赞成功,-1:操作失败,2:表示已经点过赞了| + + +返回值 +``` +{ + "status": 0, + "message": "响应成功" +} +``` +--- + +### 取消关注 +``` +DELETE /api/projects/:id/watchers/unfollow +``` +*示例* +``` +curl -X DELETE http://localhost:3000//api/projects/3263/watchers/unfollow | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|0:点赞成功,-1:操作失败,2:表示还未点赞| + + +返回值 +``` +{ + "status": 0, + "message": "响应成功" +} +``` +--- + +### 用户是否关注过项目 +``` +GET /api/projects/:id/watchers/check_watch +``` +*示例* +``` +curl -X GET http://localhost:3000/api/projects/3263/watchers/check_watch | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是 |int |项目id | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|status |int|1:已关注,0:未关注, -1:请求操作失败| + + +返回值 +``` +{ + "status": 0, + "message": "success" +} +``` +--- + +### 项目的关注者列表 +``` +GET /api/projects/:id/watchers +``` +*示例* +``` +curl -X GET \ +-d "page=1" \ +-d "limit=5" \ +http://localhost:3000//api/projects/3263/watchers | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|page |否|string |页数,第几页 | +|limit |否|string |每页多少条数据,默认15条 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|total_count |int|总条数| +|watchers |array|关注数据| +|-- name |string|用户名称| +|-- login |string|用户标识/登录名(login)| +|-- image_url |string|用户头像| + + +返回值 +``` +{ + "total_count": 1, + "watchers": [ + { + "name": "18816895620", + "login": "18816895620", + "image_url": "avatars/User/b" + } + ] +} +``` +--- + +### 仓库新建文件 +``` +DELETE /api/:login/:repo_identifier/contents +``` +*示例* +``` +curl -X POST \ +-d 'filepath=test1_create_file1.rb' \ +-d 'branch=master' \ +-d 'content=提交的内容' \ +-d 'message=test commit ' \ +http://localhost:3000/api/18816895620/mirror_demo/contents.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|string |项目id | +|filepath |是|string |文件相对于仓库的路径 | +|content |否|string |内容 | +|message |否|string |提交说明 | +|branch |否|string |分支名称, branch和new_branch必须存在一个 | +|new_branch |否|string |新的分支名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|name |string|文件名| +|sha |string|提交文件的sha值| +|size |int|文件大小, 单位:B| +|content |string|base64编码后的文件内容| +|encoding |string|编码方式| +|commit |object|| +|-- message |string|提交备注说明信息| +|-- committer|object|| +|---- name |string|用户名| +|---- email |string|用户邮箱| +|---- date |string|文件创建时间| + + + +返回值 +``` +{ + "name": "test1_create_file12.rb", + "sha": "7b70509105b587e71f5692b9e8ab70851e321f64", + "size": 12, + "content": "Wm5ObWMyRmtaZz09", + "encoding": "base64", + "commit": { + "message": "good luck\n", + "author": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-07T03:31:20Z" + }, + "committer": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-07T03:31:20Z" + } + } +} +``` +--- + +### 更新仓库中的文件 +``` +PUT /api/:login/:repo_identifier/contents/files/update +``` +*示例* +``` +curl -X PUT \ +-d 'filepath=text1.rb' \ +-d 'branch=master' \ +-d 'content=ruby code' \ +-d 'message=更改提交信息' \ +-d 'from_path=text.rb' \ +-d "sha=57426eb21e4ceabdf4b206f022077e0040" \ +http://localhost:3000/api/18816895620/mirror_demo/contents/files/update.json | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|filepath |是|string |文件相对于仓库的路径(或修改后的文件路径) | +|from_path |是|string |原文件相对于仓库的路径, 只有当需要修改原文件名称时,才需要该参数 | +|sha |是|string |文件的sha标识值 | +|content |是|string |内容 | +|message |否|string |提交说明 | +|branch |否|string |分支名称, branch和new_branch必须存在一个,且只能存在一个 | +|new_branch |否|string |新的分支名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|name |string|文件名| +|sha |string|提交文件的sha值| +|size |int|文件大小, 单位:B| +|content |string|base64编码后的文件内容| +|encoding |string|编码方式| +|commit |object|| +|-- message |string|提交备注说明信息| +|-- committer|object|| +|---- name |string|用户名| +|---- email |string|用户邮箱| +|---- date |string|文件创建时间| + + +返回值 +``` +{ + "name": "test1_create_file6.rb", + "sha": "57426eb21e4ceabdf4b206f022257e08077e0040", + "size": 16, + "content": "5o+Q5Lqk55qE5YaF5a65MQ==", + "encoding": "base64", + "commit": { + "message": "更改提交信息\n", + "author": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-08T07:05:15Z" + }, + "committer": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-08T07:05:15Z" + } + } +} +``` +--- + +### 删除仓库中的文件 +``` +DELETE /api/:login/:repo_identifier/contents/files/delete +``` +*示例* +``` +curl -X DELETE \ +-d 'filepath=test1_create_file12.rb' \ +-d 'test delete file' \ +-d 'sha=7b70509105b587e71f5692b9e8ab70851e321f64' \ +http://localhost:3000/api/18816895620/mirror_demo/contents/files/delete | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|id |是|int |项目id | +|filepath |是|string |文件相对于仓库的路径 | +|message |否|string |提交说明 | +|branch |否|string |分支名称, 默认为master分支| +|new_branch |否|string |新的分支名称 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|sha |string|提交文件的sha值| +|commit |object|| +|-- message |string|提交备注说明信息| +|-- committer|object|| +|---- name |string|用户名| +|---- email |string|用户邮箱| +|---- date |string|文件创建时间| + + +返回值 +``` +{ + "commit": { + "sha": "7b70509105b587e71f5692b9e8ab70851e321f64", + "message": "Delete 'test1_create_file11.rb'\n", + "author": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-08T07:57:34Z" + }, + "committer": { + "name": "18816895620", + "email": "2456233122@qq.com", + "date": "2020-01-08T07:57:34Z" + } + } +} +``` +--- diff --git a/docs/figs/code.png b/docs/figs/code.png new file mode 100644 index 00000000..469ee07b Binary files /dev/null and b/docs/figs/code.png differ diff --git a/docs/figs/issue_assign.png b/docs/figs/issue_assign.png new file mode 100644 index 00000000..01798d2e Binary files /dev/null and b/docs/figs/issue_assign.png differ diff --git a/docs/figs/issue_assign2.png b/docs/figs/issue_assign2.png new file mode 100644 index 00000000..ffd22764 Binary files /dev/null and b/docs/figs/issue_assign2.png differ diff --git a/docs/figs/issue_manage.png b/docs/figs/issue_manage.png new file mode 100644 index 00000000..5983daeb Binary files /dev/null and b/docs/figs/issue_manage.png differ diff --git a/docs/figs/issue_view.png b/docs/figs/issue_view.png new file mode 100644 index 00000000..582dc88a Binary files /dev/null and b/docs/figs/issue_view.png differ diff --git a/docs/figs/milestone.png b/docs/figs/milestone.png new file mode 100644 index 00000000..4a78f60b Binary files /dev/null and b/docs/figs/milestone.png differ diff --git a/dump.rdb b/dump.rdb index d12a997b..f32855aa 100644 Binary files a/dump.rdb and b/dump.rdb differ diff --git a/lib/gitlab-cli/Gemfile b/lib/gitlab-cli/Gemfile deleted file mode 100644 index 2b517aca..00000000 --- a/lib/gitlab-cli/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source 'http://gems.ruby-china.org/' - -# Specify your gem's dependencies in gitlab.gemspec -gemspec diff --git a/lib/gitlab-cli/LICENSE.txt b/lib/gitlab-cli/LICENSE.txt deleted file mode 100644 index d3cbb552..00000000 --- a/lib/gitlab-cli/LICENSE.txt +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2012-2014 Nihad Abbasov -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/gitlab-cli/README.md b/lib/gitlab-cli/README.md deleted file mode 100644 index 1a1f0e4b..00000000 --- a/lib/gitlab-cli/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# Gitlab - -[![Build Status](https://travis-ci.org/NARKOZ/gitlab.png)](http://travis-ci.org/NARKOZ/gitlab) - -[website](http://narkoz.github.io/gitlab) | -[documentation](http://rubydoc.info/gems/gitlab/frames) - -Gitlab is a Ruby wrapper and CLI for the [GitLab API](https://github.com/gitlabhq/gitlabhq/tree/master/doc/api#gitlab-api). - -## Installation - -Install it from rubygems: - -```sh -gem install gitlab -``` - -Or add to a Gemfile: - -```ruby -gem 'gitlab' -# gem 'gitlab', :git => 'git://github.com/NARKOZ/gitlab.git' -``` - -## Usage - -Configuration example: - -```ruby -Gitlab.configure do |config| - config.endpoint = 'https://example.net/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT'] - config.private_token = 'qEsq1pt6HJPaNciie3MG' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN'] - # Optional - # config.user_agent = 'Custom User Agent' # user agent, default: 'Gitlab Ruby Gem [version]' - # config.sudo = 'user' # username for sudo mode, default: nil -end -``` - -(Note: If you are using Gitlab.com's hosted service, your endpoint will be `https://gitlab.com/api/v3`) - -Usage examples: - -```ruby -# set an API endpoint -Gitlab.endpoint = 'http://example.net/api/v3' -# => "http://example.net/api/v3" - -# set a user private token -Gitlab.private_token = 'qEsq1pt6HJPaNciie3MG' -# => "qEsq1pt6HJPaNciie3MG" - -# list projects -Gitlab.projects(:per_page => 5) -# => [#1, "code"=>"brute", "name"=>"Brute", "description"=>nil, "path"=>"brute", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:56Z"}>, #2, "code"=>"mozart", "name"=>"Mozart", "description"=>nil, "path"=>"mozart", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:57Z"}>, #3, "code"=>"gitlab", "name"=>"Gitlab", "description"=>nil, "path"=>"gitlab", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:58Z"}>] - -# initialize a new client -g = Gitlab.client(:endpoint => 'https://api.example.com', :private_token => 'qEsq1pt6HJPaNciie3MG') -# => # - -# get a user -user = g.user -# => #1, "email"=>"john@example.com", "name"=>"John Smith", "bio"=>nil, "skype"=>"", "linkedin"=>"", "twitter"=>"john", "dark_scheme"=>false, "theme_id"=>1, "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}> - -# get a user's email -user.email -# => "john@example.com" - -# set a sudo mode to perform API calls as another user -Gitlab.sudo = 'other_user' -# => "other_user" - -# disable a sudo mode -Gitlab.sudo = nil -# => nil -``` - -For more information, refer to [documentation](http://rubydoc.info/gems/gitlab/frames). - -## CLI - -Usage examples: - -```sh -# list users -gitlab users - -# get current user -gitlab user - -# get a user -gitlab user 2 - -# filter output -gitlab user --only=id,username - -gitlab user --except=email,bio -``` - -## CLI Shell - -Usage examples: - -```sh -# start shell session -gitlab shell - -# list available commands -gitlab> help - -# list groups -gitlab> groups - -# protect a branch -gitlab> protect_branch 1 master -``` - -For more information, refer to [website](http://narkoz.github.io/gitlab). - -## License - -Released under the BSD 2-clause license. See LICENSE.txt for details. diff --git a/lib/gitlab-cli/Rakefile b/lib/gitlab-cli/Rakefile deleted file mode 100644 index eebc7761..00000000 --- a/lib/gitlab-cli/Rakefile +++ /dev/null @@ -1,9 +0,0 @@ -require "bundler/gem_tasks" - -require 'rspec/core/rake_task' -RSpec::Core::RakeTask.new(:spec) do |spec| - spec.pattern = FileList['spec/**/*_spec.rb'] - spec.rspec_opts = ['--color', '--format d'] -end - -task :default => :spec diff --git a/lib/gitlab-cli/bin/gitlab b/lib/gitlab-cli/bin/gitlab deleted file mode 100755 index 02cc41fc..00000000 --- a/lib/gitlab-cli/bin/gitlab +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env ruby - -$:.unshift File.expand_path('../../lib', __FILE__) - -require 'gitlab/cli' - -Gitlab::CLI.start(ARGV) diff --git a/lib/gitlab-cli/gitlab.gemspec b/lib/gitlab-cli/gitlab.gemspec deleted file mode 100644 index 11bd093d..00000000 --- a/lib/gitlab-cli/gitlab.gemspec +++ /dev/null @@ -1,26 +0,0 @@ -# -*- encoding: utf-8 -*- -lib = File.expand_path('../lib', __FILE__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'gitlab/version' - -Gem::Specification.new do |gem| - gem.name = "gitlab" - gem.version = Gitlab::VERSION - gem.authors = ["Nihad Abbasov"] - gem.email = ["mail@narkoz.me"] - gem.description = %q{Ruby client and CLI for GitLab API} - gem.summary = %q{A Ruby wrapper and CLI for the GitLab API} - gem.homepage = "https://github.com/narkoz/gitlab" - - gem.files = `git ls-files`.split($/) - gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } - gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) - gem.require_paths = ["lib"] - - gem.add_runtime_dependency 'httparty' - gem.add_runtime_dependency 'terminal-table' - - gem.add_development_dependency 'rake' - gem.add_development_dependency 'rspec' - gem.add_development_dependency 'webmock' -end diff --git a/lib/gitlab-cli/lib/gitlab.rb b/lib/gitlab-cli/lib/gitlab.rb deleted file mode 100644 index a203a70a..00000000 --- a/lib/gitlab-cli/lib/gitlab.rb +++ /dev/null @@ -1,37 +0,0 @@ -require 'gitlab/version' -require 'gitlab/objectified_hash' -require 'gitlab/configuration' -require 'gitlab/error' -require 'gitlab/request' -require 'gitlab/api' -require 'gitlab/client' - -module Gitlab - extend Configuration - - # Alias for Gitlab::Client.new - # - # @return [Gitlab::Client] - def self.client(options={}) - Gitlab::Client.new(options) - end - - # Delegate to Gitlab::Client - def self.method_missing(method, *args, &block) - return super unless client.respond_to?(method) - client.send(method, *args, &block) - end - - # Delegate to Gitlab::Client - def self.respond_to?(method) - return client.respond_to?(method) || super - end - - # Returns an unsorted array of available client methods. - # - # @return [Array] - def self.actions - hidden = /endpoint|private_token|user_agent|sudo|get|post|put|\Adelete\z|validate|set_request_defaults/ - (Gitlab::Client.instance_methods - Object.methods).reject {|e| e[hidden]} - end -end diff --git a/lib/gitlab-cli/lib/gitlab/api.rb b/lib/gitlab-cli/lib/gitlab/api.rb deleted file mode 100644 index c2dfb7cf..00000000 --- a/lib/gitlab-cli/lib/gitlab/api.rb +++ /dev/null @@ -1,17 +0,0 @@ -module Gitlab - # @private - class API < Request - # @private - attr_accessor(*Configuration::VALID_OPTIONS_KEYS) - - # Creates a new API. - # @raise [Error:MissingCredentials] - def initialize(options={}) - options = Gitlab.options.merge(options) - Configuration::VALID_OPTIONS_KEYS.each do |key| - send("#{key}=", options[key]) - end - set_request_defaults @endpoint, @private_token, @sudo - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/cli.rb b/lib/gitlab-cli/lib/gitlab/cli.rb deleted file mode 100644 index fa6d6d67..00000000 --- a/lib/gitlab-cli/lib/gitlab/cli.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'gitlab' -require 'terminal-table/import' -require_relative 'cli_helpers' -require_relative 'shell' - -class Gitlab::CLI - extend Helpers - - def self.start(args) - command = args.shift.strip rescue 'help' - run(command, args) - end - - def self.run(cmd, args=[]) - case cmd - when 'help' - puts actions_table - when 'info' - endpoint = Gitlab.endpoint ? Gitlab.endpoint : 'not set' - private_token = Gitlab.private_token ? Gitlab.private_token : 'not set' - puts "Gitlab endpoint is #{endpoint}" - puts "Gitlab private token is #{private_token}" - puts "Ruby Version is #{RUBY_VERSION}" - puts "Gitlab Ruby Gem #{Gitlab::VERSION}" - when '-v', '--version' - puts "Gitlab Ruby Gem #{Gitlab::VERSION}" - when 'shell' - Gitlab::Shell.start - else - unless valid_command?(cmd) - puts "Unknown command. Run `gitlab help` for a list of available commands." - exit(1) - end - - if args.any? && (args.last.start_with?('--only=') || args.last.start_with?('--except=')) - command_args = args[0..-2] - else - command_args = args - end - - confirm_command(cmd) - - data = gitlab_helper(cmd, command_args) { exit(1) } - output_table(cmd, args, data) - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/cli_helpers.rb b/lib/gitlab-cli/lib/gitlab/cli_helpers.rb deleted file mode 100644 index 93293d38..00000000 --- a/lib/gitlab-cli/lib/gitlab/cli_helpers.rb +++ /dev/null @@ -1,175 +0,0 @@ -class Gitlab::CLI - # Defines methods related to CLI output and formatting. - module Helpers - extend self - - # Returns filtered required fields. - # - # @return [Array] - def required_fields(args) - if args.any? && args.last.start_with?('--only=') - args.last.gsub('--only=', '').split(',') - else - [] - end - end - - # Returns filtered excluded fields. - # - # @return [Array] - def excluded_fields(args) - if args.any? && args.last.start_with?('--except=') - args.last.gsub('--except=', '').split(',') - else - [] - end - end - - # Confirms command is valid. - # - # @return [Boolean] - def valid_command?(cmd) - command = cmd.is_a?(Symbol) ? cmd : cmd.to_sym - Gitlab.actions.include?(command) - end - - # Confirms command with a desctructive action. - # - # @return [String] - def confirm_command(cmd) - if cmd.start_with?('remove_') || cmd.start_with?('delete_') - puts "Are you sure? (y/n)" - if %w(y yes).include?($stdin.gets.to_s.strip.downcase) - puts 'Proceeding..' - else - puts 'Command aborted.' - exit(1) - end - end - end - - # Table with available commands. - # - # @return [String] - def actions_table - client = Gitlab::Client.new(endpoint: '') - actions = Gitlab.actions - methods = [] - - actions.each do |action| - methods << { - name: action, - owner: client.method(action).owner.to_s.gsub('Gitlab::Client::', '') - } - end - - owners = methods.map {|m| m[:owner]}.uniq.sort - methods_c = methods.group_by {|m| m[:owner]} - methods_c = methods_c.map {|_, v| [_, v.sort_by {|hv| hv[:name]}] } - methods_c = Hash[methods_c.sort_by(&:first).map {|k, v| [k, v]}] - max_column_length = methods_c.values.max_by(&:size).size - - rows = max_column_length.times.map do |i| - methods_c.keys.map do |key| - methods_c[key][i] ? methods_c[key][i][:name] : '' - end - end - - table do |t| - t.title = "Available commands (#{actions.size} total)" - t.headings = owners - - rows.each do |row| - t.add_row row - end - end - end - - # Decides which table to use. - # - # @return [String] - def output_table(cmd, args, data) - case data - when Gitlab::ObjectifiedHash - puts single_record_table(data, cmd, args) - when Array - puts multiple_record_table(data, cmd, args) - else - puts data.inspect - end - end - - # Table for a single record. - # - # @return [String] - def single_record_table(data, cmd, args) - hash = data.to_h - keys = hash.keys.sort {|x, y| x.to_s <=> y.to_s } - keys = keys & required_fields(args) if required_fields(args).any? - keys = keys - excluded_fields(args) - - table do |t| - t.title = "Gitlab.#{cmd} #{args.join(', ')}" - - keys.each_with_index do |key, index| - case value = hash[key] - when Hash - value = 'Hash' - when nil - value = 'null' - end - - t.add_row [key, value] - t.add_separator unless keys.size - 1 == index - end - end - end - - # Table for multiple records. - # - # @return [String] - def multiple_record_table(data, cmd, args) - return 'No data' if data.empty? - - arr = data.map(&:to_h) - keys = arr.first.keys.sort {|x, y| x.to_s <=> y.to_s } - keys = keys & required_fields(args) if required_fields(args).any? - keys = keys - excluded_fields(args) - - table do |t| - t.title = "Gitlab.#{cmd} #{args.join(', ')}" - t.headings = keys - - arr.each_with_index do |hash, index| - values = [] - - keys.each do |key| - case value = hash[key] - when Hash - value = 'Hash' - when nil - value = 'null' - end - - values << value - end - - t.add_row values - t.add_separator unless arr.size - 1 == index - end - end - end - - # Helper function to call Gitlab commands with args. - def gitlab_helper(cmd, args=[]) - begin - data = args.any? ? Gitlab.send(cmd, *args) : Gitlab.send(cmd) - rescue => e - puts e.message - yield if block_given? - end - - data - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client.rb b/lib/gitlab-cli/lib/gitlab/client.rb deleted file mode 100644 index a2616391..00000000 --- a/lib/gitlab-cli/lib/gitlab/client.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Gitlab - # Wrapper for the Gitlab REST API. - class Client < API - Dir[File.expand_path('../client/*.rb', __FILE__)].each {|f| require f} - - include Branches - include Groups - include Issues - include MergeRequests - include Milestones - include Notes - include Projects - include Repositories - include Snippets - include SystemHooks - include Users - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client/branches.rb b/lib/gitlab-cli/lib/gitlab/client/branches.rb deleted file mode 100644 index bbe55498..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/branches.rb +++ /dev/null @@ -1,79 +0,0 @@ -class Gitlab::Client - # Defines methods related to repositories. - module Branches - # Gets a list of project repositiory branches. - # - # @example - # Gitlab.branches(42) - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def branches(project, options={}) - get("/projects/#{project}/repository/branches", :query => options) - end - alias_method :repo_branches, :branches - - # Gets information about a repository branch. - # - # @example - # Gitlab.branch(3, 'api') - # Gitlab.repo_branch(5, 'master') - # - # @param [Integer] project The ID of a project. - # @param [String] branch The name of the branch. - # @return [Gitlab::ObjectifiedHash] - def branch(project, branch) - get("/projects/#{project}/repository/branches/#{branch}") - end - - alias_method :repo_branch, :branch - - # Protects a repository branch. - # - # @example - # Gitlab.protect_branch(3, 'api') - # Gitlab.repo_protect_branch(5, 'master') - # - # @param [Integer] project The ID of a project. - # @param [String] branch The name of the branch. - # @return [Gitlab::ObjectifiedHash] - def protect_branch(project, branch) - put("/projects/#{project}/repository/branches/#{branch}/protect") - end - alias_method :repo_protect_branch, :protect_branch - - # Unprotects a repository branch. - # - # @example - # Gitlab.unprotect_branch(3, 'api') - # Gitlab.repo_unprotect_branch(5, 'master') - # - # @param [Integer] project The ID of a project. - # @param [String] branch The name of the branch. - # @return [Gitlab::ObjectifiedHash] - def unprotect_branch(project, branch) - put("/projects/#{project}/repository/branches/#{branch}/unprotect") - end - alias_method :repo_unprotect_branch, :unprotect_branch - - # Creates a repository branch. Requires Gitlab >= 6.8.x - # - # @example - # Gitlab.create_branch(3, 'api') - # Gitlab.repo_create_branch(5, 'master') - # - # @param [Integer] project The ID of a project. - # @param [String] branch The name of the new branch. - # @param [String] ref Create branch from commit sha or existing branch - # @return [Gitlab::ObjectifiedHash] - def create_branch(project, branch, ref) - post("/projects/#{project}/repository/branches",:body => {:branch_name => branch, :ref => ref}) - end - alias_method :repo_create_branch, :create_branch - - end -end - diff --git a/lib/gitlab-cli/lib/gitlab/client/groups.rb b/lib/gitlab-cli/lib/gitlab/client/groups.rb deleted file mode 100644 index 66f5f5a7..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/groups.rb +++ /dev/null @@ -1,88 +0,0 @@ -class Gitlab::Client - # Defines methods related to groups. - module Groups - # Gets a list of groups. - # - # @example - # Gitlab.groups - # Gitlab.groups(:per_page => 40) - # - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def groups(options={}) - get("/groups", :query => options) - end - - # Gets a single group. - # - # @example - # Gitlab.group(42) - # - # @param [Integer] id The ID of a group. - # @return [Gitlab::ObjectifiedHash] - def group(id) - get("/groups/#{id}") - end - - # Creates a new group. - # - # @param [String] name The name of a group. - # @param [String] path The path of a group. - # @return [Gitlab::ObjectifiedHash] Information about created group. - def create_group(name, path) - body = {:name => name, :path => path} - post("/groups", :body => body) - end - - # Get a list of group members. - # - # @example - # Gitlab.group_members(1) - # Gitlab.group_members(1, :per_page => 40) - # - # @param [Integer] id The ID of a group. - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def group_members(id, options={}) - get("/groups/#{id}/members", :query => options) - end - - # Adds a user to group. - # - # @example - # Gitlab.add_group_member(1, 2, 40) - # - # @param [Integer] team_id The group id to add a member to. - # @param [Integer] user_id The user id of the user to add to the team. - # @param [Integer] access_level Project access level. - # @return [Gitlab::ObjectifiedHash] Information about added team member. - def add_group_member(team_id, user_id, access_level) - post("/groups/#{team_id}/members", :body => {:user_id => user_id, :access_level => access_level}) - end - - # Removes user from user group. - # - # @example - # Gitlab.remove_group_member(1, 2) - # - # @param [Integer] team_id The group ID. - # @param [Integer] user_id The ID of a user. - # @return [Gitlab::ObjectifiedHash] Information about removed team member. - def remove_group_member(team_id, user_id) - delete("/groups/#{team_id}/members/#{user_id}") - end - - # Transfers a project to a group - # - # @param [Integer] id The ID of a group. - # @param [Integer] project_id The ID of a project. - def transfer_project_to_group(id, project_id) - body = {:id => id, :project_id => project_id} - post("/groups/#{id}/projects/#{project_id}", :body => body) - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client/issues.rb b/lib/gitlab-cli/lib/gitlab/client/issues.rb deleted file mode 100644 index 668953d1..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/issues.rb +++ /dev/null @@ -1,92 +0,0 @@ -class Gitlab::Client - # Defines methods related to issues. - module Issues - # Gets a list of user's issues. - # Will return a list of project's issues if project ID passed. - # - # @example - # Gitlab.issues - # Gitlab.issues(5) - # Gitlab.issues(:per_page => 40) - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def issues(project=nil, options={}) - if project.to_i.zero? - get("/issues", :query => options) - else - get("/projects/#{project}/issues", :query => options) - end - end - - # Gets a single issue. - # - # @example - # Gitlab.issue(5, 42) - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of an issue. - # @return [Gitlab::ObjectifiedHash] - def issue(project, id) - get("/projects/#{project}/issues/#{id}") - end - - # Creates a new issue. - # - # @param [Integer] project The ID of a project. - # @param [String] title The title of an issue. - # @param [Hash] options A customizable set of options. - # @option options [String] :description The description of an issue. - # @option options [Integer] :assignee_id The ID of a user to assign issue. - # @option options [Integer] :milestone_id The ID of a milestone to assign issue. - # @option options [String] :labels Comma-separated label names for an issue. - # @return [Gitlab::ObjectifiedHash] Information about created issue. - def create_issue(project, title, options={}) - body = {:title => title}.merge(options) - post("/projects/#{project}/issues", :body => body) - end - - # Updates an issue. - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of an issue. - # @param [Hash] options A customizable set of options. - # @option options [String] :title The title of an issue. - # @option options [String] :description The description of an issue. - # @option options [Integer] :assignee_id The ID of a user to assign issue. - # @option options [Integer] :milestone_id The ID of a milestone to assign issue. - # @option options [String] :labels Comma-separated label names for an issue. - # @option options [String] :state_event The state event of an issue ('close' or 'reopen'). - # @return [Gitlab::ObjectifiedHash] Information about updated issue. - def edit_issue(project, id, options={}) - put("/projects/#{project}/issues/#{id}", :body => options) - end - - # Closes an issue. - # - # @example - # Gitlab.close_issue(3, 42) - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of an issue. - # @return [Gitlab::ObjectifiedHash] Information about closed issue. - def close_issue(project, id) - put("/projects/#{project}/issues/#{id}", :body => {:state_event => 'close'}) - end - - # Reopens an issue. - # - # @example - # Gitlab.reopen_issue(3, 42) - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of an issue. - # @return [Gitlab::ObjectifiedHash] Information about reopened issue. - def reopen_issue(project, id) - put("/projects/#{project}/issues/#{id}", :body => {:state_event => 'reopen'}) - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client/merge_requests.rb b/lib/gitlab-cli/lib/gitlab/client/merge_requests.rb deleted file mode 100644 index e15f7dfa..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/merge_requests.rb +++ /dev/null @@ -1,135 +0,0 @@ -class Gitlab::Client - # Defines methods related to merge requests. - module MergeRequests - # Gets a list of project merge requests. - # - # @example - # Gitlab.merge_requests(5) - # Gitlab.merge_requests(:per_page => 40) - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def merge_requests(project, options={}) - get("/projects/#{project}/merge_requests", :query => options) - end - - # Gets a single merge request. - # - # @example - # Gitlab.merge_request(5, 36) - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a merge request. - # @return 'source_branch', :target_branch => 'target_branch') - # Gitlab.create_merge_request(5, 'New merge request', - # :source_branch => 'source_branch', :target_branch => 'target_branch', :assignee_id => 42) - # - # @param [Integer] project The ID of a project. - # @param [String] title The title of a merge request. - # @param [Hash] options A customizable set of options. - # @option options [String] :source_branch (required) The source branch name. - # @option options [String] :target_branch (required) The target branch name. - # @option options [Integer] :assignee_id (optional) The ID of a user to assign merge request. - # @return [Gitlab::ObjectifiedHash] Information about created merge request. - def create_merge_request(project, title, gid, options={}) - check_attributes!(options, [:source_branch, :target_branch]) - - body = {:title => title}.merge(options) - post("/projects/#{project}/merge_requests?user_id=#{gid}", :body => body) - end - - # Updates a merge request. - # - # @example - # Gitlab.update_merge_request(5, 42, :title => 'New title') - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a merge request. - # @param [Hash] options A customizable set of options. - # @option options [String] :title The title of a merge request. - # @option options [String] :source_branch The source branch name. - # @option options [String] :target_branch The target branch name. - # @option options [Integer] :assignee_id The ID of a user to assign merge request. - # @option options [String] :state_event New state (close|reopen|merge). - # @return [Gitlab::ObjectifiedHash] Information about updated merge request. - def update_merge_request(project, id, gid, options={}) - put("/projects/#{project}/merge_request/#{id}?user_id=#{gid}", :body => options) - end - - # Adds a comment to a merge request. - # - # @example - # Gitlab.create_merge_request_comment(5, 1, "Awesome merge!") - # Gitlab.create_merge_request_comment('gitlab', 1, "Awesome merge!") - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a merge request. - # @param [String] note The content of a comment. - # @return [Gitlab::ObjectifiedHash] Information about created merge request comment. - def create_merge_request_comment(project, id, note, gid) - post("/projects/#{project}/merge_request/#{id}/comments?user_id=#{gid}", :body => {:note => note}) - end - - # Get a list of merge request commits. - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - The ID of MR - def merge_request_commits(project, id) - get("/projects/#{project}/merge_request/#{id}/commits") - end - - # Shows information about the merge request including its files and changes. With GitLab 8.2 the return fields upvotes and downvotes are deprecated and always return 0. - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - The ID of MR - def merge_request_changes(project, id) - get("/projects/#{project}/merge_request/#{id}/changes") - end - - # Gets the comments on a merge request. - # - # @example - # Gitlab.merge_request_comments(5, 1) - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a merge request. - # @return [Gitlab::ObjectifiedHash] The merge request's comments. - def merge_request_comments(project, id) - get("/projects/#{project}/merge_request/#{id}/comments") - end - - # Accept a merge request. - # - # @example - # Gitlab.accept_pull_rquest(5, 1) - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a merge request. - # @return [Gitlab::ObjectifiedHash] - def accept_merge_rquest(project, id, gid) - put("/projects/#{project}/merge_request/#{id}/merge?user_id=#{gid}") - end - - private - - def check_attributes!(options, attrs) - attrs.each do |attr| - unless options.has_key?(attr) || options.has_key?(attr.to_s) - raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter") - end - end - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client/milestones.rb b/lib/gitlab-cli/lib/gitlab/client/milestones.rb deleted file mode 100644 index 197b1f3c..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/milestones.rb +++ /dev/null @@ -1,57 +0,0 @@ -class Gitlab::Client - # Defines methods related to milestones. - module Milestones - # Gets a list of project's milestones. - # - # @example - # Gitlab.milestones(5) - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def milestones(project, options={}) - get("/projects/#{project}/milestones", :query => options) - end - - # Gets a single milestone. - # - # @example - # Gitlab.milestone(5, 36) - # - # @param [Integer, String] project The ID of a project. - # @param [Integer] id The ID of a milestone. - # @return [Gitlab::ObjectifiedHash] - def milestone(project, id) - get("/projects/#{project}/milestones/#{id}") - end - - # Creates a new milestone. - # - # @param [Integer] project The ID of a project. - # @param [String] title The title of a milestone. - # @param [Hash] options A customizable set of options. - # @option options [String] :description The description of a milestone. - # @option options [String] :due_date The due date of a milestone. - # @return [Gitlab::ObjectifiedHash] Information about created milestone. - def create_milestone(project, title, options={}) - body = {:title => title}.merge(options) - post("/projects/#{project}/milestones", :body => body) - end - - # Updates a milestone. - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a milestone. - # @param [Hash] options A customizable set of options. - # @option options [String] :title The title of a milestone. - # @option options [String] :description The description of a milestone. - # @option options [String] :due_date The due date of a milestone. - # @option options [String] :state_event The state of a milestone ('close' or 'activate'). - # @return [Gitlab::ObjectifiedHash] Information about updated milestone. - def edit_milestone(project, id, options={}) - put("/projects/#{project}/milestones/#{id}", :body => options) - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client/notes.rb b/lib/gitlab-cli/lib/gitlab/client/notes.rb deleted file mode 100644 index 9f53f4df..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/notes.rb +++ /dev/null @@ -1,106 +0,0 @@ -class Gitlab::Client - # Defines methods related to notes. - module Notes - # Gets a list of projects notes. - # - # @example - # Gitlab.notes(5) - # - # @param [Integer] project The ID of a project. - # @return [Array] - def notes(project) - get("/projects/#{project}/notes") - end - - # Gets a list of notes for a issue. - # - # @example - # Gitlab.issue_notes(5, 10) - # - # @param [Integer] project The ID of a project. - # @param [Integer] issue The ID of an issue. - # @return [Array] - def issue_notes(project, issue) - get("/projects/#{project}/issues/#{issue}/notes") - end - - # Gets a list of notes for a snippet. - # - # @example - # Gitlab.snippet_notes(5, 1) - # - # @param [Integer] project The ID of a project. - # @param [Integer] snippet The ID of a snippet. - # @return [Array] - def snippet_notes(project, snippet) - get("/projects/#{project}/snippets/#{snippet}/notes") - end - - # Gets a single wall note. - # - # @example - # Gitlab.note(5, 15) - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a note. - # @return [Gitlab::ObjectifiedHash] - def note(project, id) - get("/projects/#{project}/notes/#{id}") - end - - # Gets a single issue note. - # - # @example - # Gitlab.issue_note(5, 10, 1) - # - # @param [Integer] project The ID of a project. - # @param [Integer] issue The ID of an issue. - # @param [Integer] id The ID of a note. - # @return [Gitlab::ObjectifiedHash] - def issue_note(project, issue, id) - get("/projects/#{project}/issues/#{issue}/notes/#{id}") - end - - # Gets a single snippet note. - # - # @example - # Gitlab.snippet_note(5, 11, 3) - # - # @param [Integer] project The ID of a project. - # @param [Integer] snippet The ID of a snippet. - # @param [Integer] id The ID of an note. - # @return [Gitlab::ObjectifiedHash] - def snippet_note(project, snippet, id) - get("/projects/#{project}/snippets/#{snippet}/notes/#{id}") - end - - # Creates a new wall note. - # - # @param [Integer] project The ID of a project. - # @param [String] body The body of a note. - # @return [Gitlab::ObjectifiedHash] Information about created note. - def create_note(project, body) - post("/projects/#{project}/notes", :body => {:body => body}) - end - - # Creates a new issue note. - # - # @param [Integer] project The ID of a project. - # @param [Integer] issue The ID of an issue. - # @param [String] body The body of a note. - # @return [Gitlab::ObjectifiedHash] Information about created note. - def create_issue_note(project, issue, body) - post("/projects/#{project}/issues/#{issue}/notes", :body => {:body => body}) - end - - # Creates a new snippet note. - # - # @param [Integer] project The ID of a project. - # @param [Integer] snippet The ID of a snippet. - # @param [String] body The body of a note. - # @return [Gitlab::ObjectifiedHash] Information about created note. - def create_snippet_note(project, snippet, body) - post("/projects/#{project}/snippets/#{snippet}/notes", :body => {:body => body}) - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client/projects.rb b/lib/gitlab-cli/lib/gitlab/client/projects.rb deleted file mode 100644 index 4fd8851a..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/projects.rb +++ /dev/null @@ -1,328 +0,0 @@ -class Gitlab::Client - # Defines methods related to projects. - module Projects - # Gets a list of projects owned by the authenticated user. - # - # @example - # Gitlab.projects - # - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @option options [String] :scope Scope of projects. 'owned' for list of projects owned by the authenticated user, 'all' to get all projects (admin only) - # @return [Array] - def projects(options={}) - if (options[:scope]) - get("/projects/#{options[:scope]}", :query => options) - else - get("/projects", :query => options) - end - end - - def current_user_project(user_id, project_name) - get("/projects/current_user_projects?user_id=#{user_id}&project_name=#{project_name}") - end - - # Gets information about a project. - # - # @example - # Gitlab.project(3) - # Gitlab.project('gitlab') - # - # @param [Integer, String] id The ID or name of a project. - # @return [Gitlab::ObjectifiedHash] - def project(id) - get("/projects/#{id}") - end - - # Gets a list of project events. - # - # @example - # Gitlab.project_events(42) - # Gitlab.project_events('gitlab') - # - # @param [Integer, String] project The ID or name of a project. - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def project_events(project, options={}) - get("/projects/#{project}/events", :query => options) - end - - # Creates a new project. - # - # @example - # Gitlab.create_project('gitlab') - # Gitlab.create_project('viking', :description => 'Awesome project') - # Gitlab.create_project('Red', :wall_enabled => false) - # - # @param [String] name The name of a project. - # @param [Hash] options A customizable set of options. - # @option options [String] :description The description of a project. - # @option options [String] :default_branch The default branch of a project. - # @option options [String] :group_id The group in which to create a project. - # @option options [String] :namespace_id The namespace in which to create a project. - # @option options [Boolean] :wiki_enabled The wiki integration for a project (0 = false, 1 = true). - # @option options [Boolean] :wall_enabled The wall functionality for a project (0 = false, 1 = true). - # @option options [Boolean] :issues_enabled The issues integration for a project (0 = false, 1 = true). - # @option options [Boolean] :snippets_enabled The snippets integration for a project (0 = false, 1 = true). - # @option options [Boolean] :merge_requests_enabled The merge requests functionality for a project (0 = false, 1 = true). - # @option options [Boolean] :public The setting for making a project public (0 = false, 1 = true). - # @option options [Integer] :user_id The user/owner id of a project. - # @return [Gitlab::ObjectifiedHash] Information about created project. - def create_project(name, options={}) - url = options[:user_id] ? "/projects/user/#{options[:user_id]}" : "/projects" - post(url, :body => {:name => name}.merge(options)) - end - - # Updates a project team member to a specified access level. - # id (required) - The ID of a project - # name (optional) - project name - # path (optional) - repository name for project - # description (optional) - short project description - # default_branch (optional) - # issues_enabled (optional) - # merge_requests_enabled (optional) - # wiki_enabled (optional) - # snippets_enabled (optional) - # public (optional) - if true same as setting visibility_level = 20 - # visibility_level (optional) - - def edit_project(id, name, path) - put("/projects/#{id}", :body => {:name => name, :path => path}) - end - - # Deletes a project. - # - # @example - # Gitlab.delete_project(4) - # - # @param [Integer, String] id The ID or name of a project. - # @return [Gitlab::ObjectifiedHash] Information about deleted project. - def delete_project(id) - delete("/projects/#{id}") - end - - # Gets a list of project team members. - # - # @example - # Gitlab.team_members(42) - # Gitlab.team_members('gitlab') - # - # @param [Integer, String] project The ID or name of a project. - # @param [Hash] options A customizable set of options. - # @option options [String] :query The search query. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def team_members(project, options={}) - get("/projects/#{project}/members", :query => options) - end - - # Gets a project team member. - # - # @example - # Gitlab.team_member('gitlab', 2) - # - # @param [Integer, String] project The ID or name of a project. - # @param [Integer] id The ID of a project team member. - # @return [Gitlab::ObjectifiedHash] - def team_member(project, id) - get("/projects/#{project}/members/#{id}") - end - - # Adds a user to project team. - # - # @example - # Gitlab.add_team_member('gitlab', 2, 40) - # - # @param [Integer, String] project The ID or name of a project. - # @param [Integer] id The ID of a user. - # @param [Integer] access_level The access level to project. - # @param [Hash] options A customizable set of options. - # @return [Gitlab::ObjectifiedHash] Information about added team member. - def add_team_member(project, id, access_level) - post("/projects/#{project}/members", :body => {:user_id => id, :access_level => access_level}) - end - - # Updates a team member's project access level. - # - # @example - # Gitlab.edit_team_member('gitlab', 3, 20) - # - # @param [Integer, String] project The ID or name of a project. - # @param [Integer] id The ID of a user. - # @param [Integer] access_level The access level to project. - # @param [Hash] options A customizable set of options. - # @return [Array] Information about updated team member. - def edit_team_member(project, id, access_level) - put("/projects/#{project}/members/#{id}", :body => {:access_level => access_level}) - end - - # Removes a user from project team. - # - # @example - # Gitlab.remove_team_member('gitlab', 2) - # - # @param [Integer, String] project The ID or name of a project. - # @param [Integer] id The ID of a user. - # @param [Hash] options A customizable set of options. - # @return [Gitlab::ObjectifiedHash] Information about removed team member. - def remove_team_member(project, id) - delete("/projects/#{project}/members/#{id}") - end - - # Gets a list of project hooks. - # - # @example - # Gitlab.project_hooks(42) - # Gitlab.project_hooks('gitlab') - # - # @param [Integer, String] project The ID or name of a project. - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def project_hooks(project, options={}) - get("/projects/#{project}/hooks", :query => options) - end - - # Gets a project hook. - # - # @example - # Gitlab.project_hook(42, 5) - # Gitlab.project_hook('gitlab', 5) - # - # @param [Integer, String] project The ID or name of a project. - # @param [Integer] id The ID of a hook. - # @return [Gitlab::ObjectifiedHash] - def project_hook(project, id) - get("/projects/#{project}/hooks/#{id}") - end - - # Adds a new hook to the project. - # - # @example - # Gitlab.add_project_hook(42, 'https://api.example.net/v1/webhooks/ci') - # - # @param [Integer, String] project The ID or name of a project. - # @param [String] url The hook URL. - # @param [Hash] options Events list (`{push_events: true, merge_requests_events: false}`). - # @return [Gitlab::ObjectifiedHash] Information about added hook. - def add_project_hook(project, url, options = {}) - available_events = [:push_events, :merge_requests_events, :issues_events] - passed_events = available_events.select { |event| options[event] } - events = Hash[passed_events.map { |event| [event, options[event]] }] - - post("/projects/#{project}/hooks", :body => {:url => url}.merge(events)) - end - - # Updates a project hook URL. - # - # @example - # Gitlab.edit_project_hook(42, 1, 'https://api.example.net/v1/webhooks/ci') - # - # @param [Integer, String] project The ID or name of a project. - # @param [Integer] id The ID of the hook. - # @param [String] url The hook URL. - # @return [Gitlab::ObjectifiedHash] Information about updated hook. - def edit_project_hook(project, id, url) - put("/projects/#{project}/hooks/#{id}", :body => {:url => url}) - end - - # Deletes a hook from project. - # - # @example - # Gitlab.delete_project_hook('gitlab', 4) - # - # @param [Integer, String] project The ID or name of a project. - # @param [String] id The ID of the hook. - # @return [Gitlab::ObjectifiedHash] Information about deleted hook. - def delete_project_hook(project, id) - delete("/projects/#{project}/hooks/#{id}") - end - - # Forks a project into the user namespace of the authenticated user. - # @param [Integer] - The ID of the project to be forked - def fork(gpid, gid) - post ("/projects/fork/#{gpid}?user_id=#{gid}") - # post("/projects/fork/#{id}") - end - - # Mark this project as forked from the other - # - # @example - # Gitlab.make_forked(42, 24) - # - # @param [Integer, String] project The ID or name of a project. - # @param [Integer] id The ID of the project it is forked from. - # @return [Gitlab::ObjectifiedHash] Information about the forked project. - def make_forked_from(project, id) - post("/projects/#{project}/fork/#{id}") - end - - # Remove a forked_from relationship for a project. - # - # @example - # Gitlab.remove_forked(42) - # - # @param [Integer, String] project The ID or name of a project. - # @param [Integer] project The ID of the project it is forked from - # @return [Gitlab::ObjectifiedHash] Information about the forked project. - def remove_forked(project) - delete("/projects/#{project}/fork") - end - - # Gets a project deploy keys. - # - # @example - # Gitlab.deploy_keys(42) - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def deploy_keys(project, options={}) - get("/projects/#{project}/keys", :query => options) - end - - # Gets a single project deploy key. - # - # @example - # Gitlab.deploy_key(42, 1) - # - # @param [Integer, String] project The ID of a project. - # @param [Integer] id The ID of a deploy key. - # @return [Gitlab::ObjectifiedHash] - def deploy_key(project, id) - get("/projects/#{project}/keys/#{id}") - end - - # Creates a new deploy key. - # - # @example - # Gitlab.create_deploy_key(42, 'My Key', 'Key contents') - # - # @param [Integer] project The ID of a project. - # @param [String] title The title of a deploy key. - # @param [String] key The content of a deploy key. - # @return [Gitlab::ObjectifiedHash] Information about created deploy key. - def create_deploy_key(project, title, key) - post("/projects/#{project}/keys", body: {title: title, key: key}) - end - - # Deletes a deploy key from project. - # - # @example - # Gitlab.delete_deploy_key(42, 1) - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a deploy key. - # @return [Gitlab::ObjectifiedHash] Information about deleted deploy key. - def delete_deploy_key(project, id) - delete("/projects/#{project}/keys/#{id}") - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client/repositories.rb b/lib/gitlab-cli/lib/gitlab/client/repositories.rb deleted file mode 100644 index c88337f5..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/repositories.rb +++ /dev/null @@ -1,213 +0,0 @@ -class Gitlab::Client - # Defines methods related to repositories. - module Repositories - - def trees(project, options={}) - get "/projects/#{project}/repository/tree", query: options - end - alias_method :repo_trees, :trees - - def files(project, file_path, ref) - get "/projects/#{project}/repository/files", query: {file_path: file_path, ref: ref} - end - alias_method :repo_files, :files - - def file_blob(project, options={}) - get("/projects/#{project}/repository/blobs", query: options) - end - # Gets a list of project repository tags. - # - # @example - # Gitlab.tags(42) - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def tags(project, options={}) - get("/projects/#{project}/repository/tags", :query => options) - end - alias_method :repo_tags, :tags - - # Creates a new project repository tag. - # - # @example - # Gitlab.create_tag(42,'new_tag','master') - # - # @param [Integer] project The ID of a project. - # @param [String] tag_name The name of the new tag. - # @param [String] ref The ref (commit sha, branch name, or another tag) the tag will point to. - # @return [Gitlab::ObjectifiedHash] - def create_tag(project, tag_name, ref) - post("/projects/#{project}/repository/tags", body: {tag_name: tag_name, ref: ref}) - end - alias_method :repo_create_tag, :create_tag - - # Gets a list of project commits. - # - # @example - # Gitlab.commits('viking') - # Gitlab.repo_commits('gitlab', :ref_name => 'api') - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [String] :ref_name The branch or tag name of a project repository. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @option options [String] :search The obj of results's search value. - # @return [Array] - def commits(project, options={}) - get("/projects/#{project}/repository/commits", :query => options) - end - alias_method :repo_commits, :commits - - # Gets a list of project commits. - # - # @example - # Gitlab.commits('viking') - # Gitlab.repo_commits('gitlab', :ref_name => 'api') - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [String] :ref_name The branch or tag name of a project repository. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def commits_total_count(project, options={}) - get("/projects/#{project}/repository/commits_total_count", :query => options) - end - alias_method :repo_commits, :commits_total_count - - # Gets total project commits. - # - # @example - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [String] :rev The branch or tag name of a project repository. - # @return [Hash] - def user_static(project, options={}) - get("/projects/#{project}/repository/user_static", :query => options) - end - - def get_branch_commit_id(project, git_tree, ref_name) - get("/projects/#{project}/repository/get_branch_commit_id?git_tree=#{git_tree}&ref_name=#{ref_name}") - end - - - # Gets a specific commit identified by the commit hash or name of a branch or tag. - # - # @example - # Gitlab.commit(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6') - # Gitlab.repo_commit(3, 'ed899a2f4b50b4370feeea94676502b42383c746') - # - # @param [Integer] project The ID of a project. - # @param [String] sha The commit hash or name of a repository branch or tag - # @return [Gitlab::ObjectifiedHash] - def commit(project, sha) - get("/projects/#{project}/repository/commits/#{sha}") - end - alias_method :repo_commit, :commit - - # Gets a statics of project repository. - # - # @example - # Gitlab.commits('viking') - # Gitlab.repo_commits('gitlab', :ref_name => 'api') - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [String] :ref_name The branch or tag name of a project repository. - # @option options [String] :creator The user name of a project repository. - # @option options [Integer] :period Statistics over time. 1:total 2:one month 3:one week - # @return [Array] - def rep_stats(project, options={}) - get("/projects/#{project}/repository/rep_stats", :query => options) - end - alias_method :repo_rep_stats, :rep_stats - - def rep_stats_week(project, options={}) - get("/projects/#{project}/repository/rep_stats_week", :query => options) - end - alias_method :repo_rep_stats, :rep_stats - - def rep_stats_month(project, options={}) - get("/projects/#{project}/repository/rep_stats_month", :query => options) - end - alias_method :repo_rep_stats, :rep_stats - - def rep_user_stats(project, options={}) - get("/projects/#{project}/repository/rep_user_stats", :query => options) - end - alias_method :repo_rep_stats, :rep_stats - - # static all users - def admin_rep_stats_week(project, options={}) - get("/projects/#{project}/repository/admin_rep_stats_week", :query => options) - end - alias_method :repo_rep_stats, :rep_stats - - def admin_rep_stats_month(project, options={}) - get("/projects/#{project}/repository/admin_rep_stats_month", :query => options) - end - alias_method :repo_rep_stats, :rep_stats - - def admin_rep_stats_all(project, options={}) - get("/projects/#{project}/repository/admin_rep_stats_all", :query => options) - end - alias_method :repo_rep_stats, :rep_stats - - # Gets a tree activities of project repository. - # - # @example - # Gitlab.commits('viking') - # Gitlab.repo_commits('gitlab', :ref_name => 'api') - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [String] :ref_name The branch or tag name of a project repository. - # @option options [String] :creator The user name of a project repository. - # @option options [Integer] :period Statistics over time. 1:total 2:one month 3:one week - # @return [Array] - def rep_last_changes(project, options={}) - get("/projects/#{project}/repository/rep_last_changes", :query => options) - end - alias_method :repo_rep_stats, :rep_stats - - # Get the diff of a commit in a project. - # - # @example - # Gitlab.commit_diff(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6') - # Gitlab.repo_commit_diff(3, 'ed899a2f4b50b4370feeea94676502b42383c746') - # - # @param [Integer] project The ID of a project. - # @param [String] sha The name of a repository branch or tag or if not given the default branch. - # @return [Gitlab::ObjectifiedHash] - def commit_diff(project, sha) - get("/projects/#{project}/repository/commits/#{sha}/diff") - end - alias_method :repo_commit_diff, :commit_diff - - # Get the commits count of each contributor in a project - # @param [Integer] project the ID fo a project. - # @return [Gitlab::ObjectifiedHash] - def contributors(project) - get("/projects/#{project}/repository/contributors") - end - - # Get an archive of the repository - # @param [Integer] project the ID fo a project. - # sha (optional) - The commit SHA to download defaults to the tip of the default branch - # @return [Gitlab::ObjectifiedHash] - def project_archive(project, sha) - get("/projects/#{project}/repository/archive?sha=#{sha}") - end - - # update file - def edit_file(project, username, options={}) - put("/projects/#{project}/repository/files?username=#{username}", :body => options) - end - - alias_method :repo_project_archive, :project_archive - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client/snippets.rb b/lib/gitlab-cli/lib/gitlab/client/snippets.rb deleted file mode 100644 index aac98560..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/snippets.rb +++ /dev/null @@ -1,86 +0,0 @@ -class Gitlab::Client - # Defines methods related to snippets. - module Snippets - # Gets a list of project's snippets. - # - # @example - # Gitlab.snippets(42) - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Gitlab::ObjectifiedHash] - def snippets(project, options={}) - get("/projects/#{project}/snippets", :query => options) - end - - # Gets information about a snippet. - # - # @example - # Gitlab.snippet(2, 14) - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a snippet. - # @return [Gitlab::ObjectifiedHash] - def snippet(project, id) - get("/projects/#{project}/snippets/#{id}") - end - - # Creates a new snippet. - # - # @example - # Gitlab.create_snippet(42, {:title => 'REST', :file_name => 'api.rb', :code => 'some code'}) - # - # @param [Integer] project The ID of a project. - # @param [Hash] options A customizable set of options. - # @option options [String] :title (required) The title of a snippet. - # @option options [String] :file_name (required) The name of a snippet file. - # @option options [String] :code (required) The content of a snippet. - # @option options [String] :lifetime (optional) The expiration date of a snippet. - # @return [Gitlab::ObjectifiedHash] Information about created snippet. - def create_snippet(project, options={}) - check_attributes!(options, [:title, :file_name, :code]) - post("/projects/#{project}/snippets", :body => options) - end - - # Updates a snippet. - # - # @example - # Gitlab.edit_snippet(42, 34, :file_name => 'README.txt') - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a snippet. - # @param [Hash] options A customizable set of options. - # @option options [String] :title The title of a snippet. - # @option options [String] :file_name The name of a snippet file. - # @option options [String] :code The content of a snippet. - # @option options [String] :lifetime The expiration date of a snippet. - # @return [Gitlab::ObjectifiedHash] Information about updated snippet. - def edit_snippet(project, id, options={}) - put("/projects/#{project}/snippets/#{id}", :body => options) - end - - # Deletes a snippet. - # - # @example - # Gitlab.delete_snippet(2, 14) - # - # @param [Integer] project The ID of a project. - # @param [Integer] id The ID of a snippet. - # @return [Gitlab::ObjectifiedHash] Information about deleted snippet. - def delete_snippet(project, id) - delete("/projects/#{project}/snippets/#{id}") - end - - private - - def check_attributes!(options, attrs) - attrs.each do |attr| - unless options.has_key?(attr) || options.has_key?(attr.to_s) - raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter") - end - end - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client/system_hooks.rb b/lib/gitlab-cli/lib/gitlab/client/system_hooks.rb deleted file mode 100644 index d8903c6d..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/system_hooks.rb +++ /dev/null @@ -1,58 +0,0 @@ -class Gitlab::Client - # Defines methods related to system hooks. - module SystemHooks - # Gets a list of system hooks. - # - # @example - # Gitlab.hooks - # Gitlab.system_hooks - # - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def hooks(options={}) - get("/hooks", query: options) - end - alias_method :system_hooks, :hooks - - # Adds a new system hook. - # - # @example - # Gitlab.add_hook('http://example.com/hook') - # Gitlab.add_system_hook('https://api.example.net/v1/hook') - # - # @param [String] url The hook URL. - # @return [Gitlab::ObjectifiedHash] - def add_hook(url) - post("/hooks", :body => {:url => url}) - end - alias_method :add_system_hook, :add_hook - - # Tests a system hook. - # - # @example - # Gitlab.hook(3) - # Gitlab.system_hook(12) - # - # @param [Integer] id The ID of a system hook. - # @return [Array] - def hook(id) - get("/hooks/#{id}") - end - alias_method :system_hook, :hook - - # Deletes a new system hook. - # - # @example - # Gitlab.delete_hook(3) - # Gitlab.delete_system_hook(12) - # - # @param [Integer] id The ID of a system hook. - # @return [Gitlab::ObjectifiedHash] - def delete_hook(id) - delete("/hooks/#{id}") - end - alias_method :delete_system_hook, :delete_hook - end -end diff --git a/lib/gitlab-cli/lib/gitlab/client/users.rb b/lib/gitlab-cli/lib/gitlab/client/users.rb deleted file mode 100644 index 6eabe097..00000000 --- a/lib/gitlab-cli/lib/gitlab/client/users.rb +++ /dev/null @@ -1,131 +0,0 @@ -class Gitlab::Client - # Defines methods related to users. - module Users - # Gets a list of users. - # - # @example - # Gitlab.users - # - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def users(options={}) - get("/users", :query => options) - end - - # Gets information about a user. - # Will return information about an authorized user if no ID passed. - # - # @example - # Gitlab.user - # Gitlab.user(2) - # - # @param [Integer] id The ID of a user. - # @return [Gitlab::ObjectifiedHash] - def user(id=nil) - id.to_i.zero? ? get("/user") : get("/users/#{id}") - end - - # Creates a new user. - # Requires authentication from an admin account. - # - # @param [String] email The email of a user. - # @param [String] password The password of a user. - # @param [Hash] options A customizable set of options. - # @option options [String] :name The name of a user. Defaults to email. - # @option options [String] :skype The skype of a user. - # @option options [String] :linkedin The linkedin of a user. - # @option options [String] :twitter The twitter of a user. - # @option options [Integer] :projects_limit The limit of projects for a user. - # @return [Gitlab::ObjectifiedHash] Information about created user. - def create_user(email, password, options={}) - body = {:email => email, :password => password, :name => email}.merge(options) - post("/users", :body => body) - end - - # Updates a user. - # - # @param [Integer] id The ID of a user. - # @param [Hash] options A customizable set of options. - # @option options [String] email The email of a user. - # @option options [String] password The password of a user. - # @option options [String] :name The name of a user. Defaults to email. - # @option options [String] :skype The skype of a user. - # @option options [String] :linkedin The linkedin of a user. - # @option options [String] :twitter The twitter of a user. - # @option options [Integer] :projects_limit The limit of projects for a user. - # @return [Gitlab::ObjectifiedHash] Information about created user. - def edit_user(user_id, options={}) - put("/users/#{user_id}", :body => options) - end - - def edit_user_email(user_id, options={}) - put("/users/#{user_id}/email", :body => options) - end - - def delete_user(user_id) - delete("/users/#{user_id}") - end - - # Creates a new user session. - # - # @example - # Gitlab.session('jack@example.com', 'secret12345') - # - # @param [String] email The email of a user. - # @param [String] password The password of a user. - # @return [Gitlab::ObjectifiedHash] - # @note This method doesn't require private_token to be set. - def session(email, password) - post("/session", :body => {:email => email, :password => password}) - end - - # Gets a list of user's SSH keys. - # - # @example - # Gitlab.ssh_keys - # - # @param [Hash] options A customizable set of options. - # @option options [Integer] :page The page number. - # @option options [Integer] :per_page The number of results per page. - # @return [Array] - def ssh_keys(options={}) - get("/user/keys", :query => options) - end - - # Gets information about SSH key. - # - # @example - # Gitlab.ssh_key(1) - # - # @param [Integer] id The ID of a user's SSH key. - # @return [Gitlab::ObjectifiedHash] - def ssh_key(id) - get("/user/keys/#{id}") - end - - # Creates a new SSH key. - # - # @example - # Gitlab.create_ssh_key('key title', 'key body') - # - # @param [String] title The title of an SSH key. - # @param [String] key The SSH key body. - # @return [Gitlab::ObjectifiedHash] Information about created SSH key. - def create_ssh_key(title, key) - post("/user/keys", :body => {:title => title, :key => key}) - end - - # Deletes an SSH key. - # - # @example - # Gitlab.delete_ssh_key(1) - # - # @param [Integer] id The ID of a user's SSH key. - # @return [Gitlab::ObjectifiedHash] Information about deleted SSH key. - def delete_ssh_key(id) - delete("/user/keys/#{id}") - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/configuration.rb b/lib/gitlab-cli/lib/gitlab/configuration.rb deleted file mode 100644 index 30a2d092..00000000 --- a/lib/gitlab-cli/lib/gitlab/configuration.rb +++ /dev/null @@ -1,39 +0,0 @@ -module Gitlab - # Defines constants and methods related to configuration. - module Configuration - # An array of valid keys in the options hash when configuring a Gitlab::API. - VALID_OPTIONS_KEYS = [:endpoint, :private_token, :user_agent, :sudo, :httparty].freeze - - # The user agent that will be sent to the API endpoint if none is set. - DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}".freeze - - # @private - attr_accessor(*VALID_OPTIONS_KEYS) - - # Sets all configuration options to their default values - # when this module is extended. - def self.extended(base) - base.reset - end - - # Convenience method to allow configuration options to be set in a block. - def configure - yield self - end - - # Creates a hash of options and their values. - def options - VALID_OPTIONS_KEYS.inject({}) do |option, key| - option.merge!(key => send(key)) - end - end - - # Resets all configuration options to the defaults. - def reset - self.endpoint = ENV['GITLAB_API_ENDPOINT'] - self.private_token = ENV['GITLAB_API_PRIVATE_TOKEN'] - self.sudo = nil - self.user_agent = DEFAULT_USER_AGENT - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/error.rb b/lib/gitlab-cli/lib/gitlab/error.rb deleted file mode 100644 index 177d261d..00000000 --- a/lib/gitlab-cli/lib/gitlab/error.rb +++ /dev/null @@ -1,45 +0,0 @@ -module Gitlab - module Error - # Custom error class for rescuing from all Gitlab errors. - class Error < StandardError; end - - # Raise when attributes are missing. - class MissingAttributes < Error; end - - # Raised when API endpoint credentials not configured. - class MissingCredentials < Error; end - - # Raised when impossible to parse response body. - class Parsing < Error; end - - # Raised when API endpoint returns the HTTP status code 400. - class BadRequest < Error; end - - # Raised when API endpoint returns the HTTP status code 401. - class Unauthorized < Error; end - - # Raised when API endpoint returns the HTTP status code 403. - class Forbidden < Error; end - - # Raised when API endpoint returns the HTTP status code 404. - class NotFound < Error; end - - # Raised when API endpoint returns the HTTP status code 405. - class MethodNotAllowed < Error; end - - # Raised when API endpoint returns the HTTP status code 406. - class DataNotAccepted < Error; end - - # Raised when API endpoint returns the HTTP status code 409. - class Conflict < Error; end - - # Raised when API endpoint returns the HTTP status code 500. - class InternalServerError < Error; end - - # Raised when API endpoint returns the HTTP status code 502. - class BadGateway < Error; end - - # Raised when API endpoint returns the HTTP status code 503. - class ServiceUnavailable < Error; end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/help.rb b/lib/gitlab-cli/lib/gitlab/help.rb deleted file mode 100644 index ccd2f2ff..00000000 --- a/lib/gitlab-cli/lib/gitlab/help.rb +++ /dev/null @@ -1,44 +0,0 @@ -require 'gitlab' -require 'gitlab/cli_helpers' - -module Gitlab::Help - extend Gitlab::CLI::Helpers - - def self.get_help(methods,cmd=nil) - help = '' - - if cmd.nil? || cmd == 'help' - help = actions_table - else - ri_cmd = `which ri`.chomp - - if $? == 0 - namespace = methods.select {|m| m[:name] === cmd }.map {|m| m[:owner]+'.'+m[:name] }.shift - - if namespace - begin - ri_output = `#{ri_cmd} -T #{namespace} 2>&1`.chomp - - if $? == 0 - ri_output.gsub!(/#{cmd}\((.*?)\)/, cmd+' \1') - ri_output.gsub!(/Gitlab\./, 'gitlab> ') - ri_output.gsub!(/Gitlab\..+$/, '') - ri_output.gsub!(/\,\s?/, ' ') - help = ri_output - else - help = "Ri docs not found for #{namespace}, please install the docs to use 'help'" - end - rescue => e - puts e.message - end - else - help = "Unknown command: #{cmd}" - end - else - help = "'ri' tool not found in your PATH, please install it to use the help." - end - end - - puts help - end -end diff --git a/lib/gitlab-cli/lib/gitlab/objectified_hash.rb b/lib/gitlab-cli/lib/gitlab/objectified_hash.rb deleted file mode 100644 index 11436da9..00000000 --- a/lib/gitlab-cli/lib/gitlab/objectified_hash.rb +++ /dev/null @@ -1,24 +0,0 @@ -module Gitlab - # Converts hashes to the objects. - class ObjectifiedHash - # Creates a new ObjectifiedHash object. - def initialize(hash) - @hash = hash - @data = hash.inject({}) do |data, (key,value)| - value = ObjectifiedHash.new(value) if value.is_a? Hash - data[key.to_s] = value - data - end - end - - def to_hash - @hash - end - alias_method :to_h, :to_hash - - # Delegate to ObjectifiedHash. - def method_missing(key) - @data.key?(key.to_s) ? @data[key.to_s] : nil - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/request.rb b/lib/gitlab-cli/lib/gitlab/request.rb deleted file mode 100644 index 49c6ef8e..00000000 --- a/lib/gitlab-cli/lib/gitlab/request.rb +++ /dev/null @@ -1,116 +0,0 @@ -require 'httparty' -require 'json' - -module Gitlab - # @private - class Request - include HTTParty - format :json - headers 'Accept' => 'application/json' - parser Proc.new { |body, _| parse(body) } - - attr_accessor :private_token - - # Converts the response body to an ObjectifiedHash. - def self.parse(body) - body = decode(body) - - if body.is_a? Hash - ObjectifiedHash.new body - elsif body.is_a? Array - body.collect! { |e| ObjectifiedHash.new(e) } - elsif body == true - body - else - raise Error::Parsing.new "Couldn't parse a response body" - end - end - - # Decodes a JSON response into Ruby object. - def self.decode(response) - begin - JSON.load response - rescue JSON::ParserError - raise Error::Parsing.new "The response is not a valid JSON" - end - end - - def get(path, options={}) - set_httparty_config(options) - set_private_token_header(options) - validate self.class.get(path, options) - end - - def post(path, options={}) - set_httparty_config(options) - set_private_token_header(options, path) - validate self.class.post(path, options) - end - - def put(path, options={}) - set_httparty_config(options) - set_private_token_header(options) - validate self.class.put(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 - - private - - # 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 - end - - # Set HTTParty configuration - # @see https://github.com/jnunemaker/httparty - def set_httparty_config(options) - if self.httparty - options.merge!(self.httparty) - end - end - - def error_message(response) - "Server responded with code #{response.code}, message: #{response.parsed_response.message}. " \ - "Request URI: #{response.request.base_uri}#{response.request.path}" - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/shell.rb b/lib/gitlab-cli/lib/gitlab/shell.rb deleted file mode 100644 index 58925b64..00000000 --- a/lib/gitlab-cli/lib/gitlab/shell.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'gitlab' -require 'gitlab/help' -require 'gitlab/cli_helpers' -require 'readline' - -class Gitlab::Shell - extend Gitlab::CLI::Helpers - - def self.start - actions = Gitlab.actions - - comp = proc { |s| actions.map(&:to_s).grep(/^#{Regexp.escape(s)}/) } - - Readline.completion_proc = comp - Readline.completion_append_character = ' ' - - client = Gitlab::Client.new(endpoint: '') - - while buf = Readline.readline('gitlab> ', true) - next if buf.nil? || buf.empty? - break if buf == 'exit' - - buf = buf.scan(/["][^"]+["]|\S+/).map { |word| word.gsub(/^['"]|['"]$/,'') } - cmd = buf.shift - args = buf.count > 0 ? buf : [] - - if cmd == 'help' - methods = [] - - actions.each do |action| - methods << { - name: action.to_s, - owner: client.method(action).owner.to_s - } - end - - args[0].nil? ? Gitlab::Help.get_help(methods) : Gitlab::Help.get_help(methods, args[0]) - next - end - - data = if actions.include?(cmd.to_sym) - confirm_command(cmd) - gitlab_helper(cmd, args) - else - "'#{cmd}' is not a valid command. See the 'help' for a list of valid commands." - end - - output_table(cmd, args, data) - end - end -end diff --git a/lib/gitlab-cli/lib/gitlab/version.rb b/lib/gitlab-cli/lib/gitlab/version.rb deleted file mode 100644 index a1783b69..00000000 --- a/lib/gitlab-cli/lib/gitlab/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module Gitlab - VERSION = "3.2.0" -end diff --git a/lib/gitlab-cli/spec/fixtures/branch.json b/lib/gitlab-cli/spec/fixtures/branch.json deleted file mode 100644 index 8756f9f6..00000000 --- a/lib/gitlab-cli/spec/fixtures/branch.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected": true} diff --git a/lib/gitlab-cli/spec/fixtures/branches.json b/lib/gitlab-cli/spec/fixtures/branches.json deleted file mode 100644 index 94aa4757..00000000 --- a/lib/gitlab-cli/spec/fixtures/branches.json +++ /dev/null @@ -1 +0,0 @@ -[{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"}},{"name":"dashboard-feed","commit":{"id":"f8f6ff065eccc6ede4d35ed87a09bb962b84ca25","parents":[{"id":"2cf8010792c3075824ee27d0f037aeb178cbbf7e"}],"tree":"e17f2157143d550891d4669c10b7446e4739bc6d","message":"add projects atom feed","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-05-31T23:42:02-07:00","committed_date":"2012-05-31T23:42:02-07:00"}},{"name":"master","commit":{"id":"2cf8010792c3075824ee27d0f037aeb178cbbf7e","parents":[{"id":"af226ae9c9af406c8a0e0bbdf364563495c2f432"},{"id":"e851cb07762aa464aae10e8b4b28de87c1a6f925"}],"tree":"6c6845838039f01723d91f395a1d2fa1dcc82522","message":"Merge pull request #868 from SaitoWu/bugfix/encoding\n\nBugfix/encoding","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-05-30T00:24:43-07:00","committed_date":"2012-05-30T00:24:43-07:00"}},{"name":"preview_notes","commit":{"id":"3749e0d99ac6bfbc65889b1b7a5310e14e7fe89a","parents":[{"id":"2483181f2c3d4ea7d2c68147b19bc07fc3937b0c"}],"tree":"f8c56161b0d6561568f088df9961362eb1ece88b","message":"pass project_id to notes preview path","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-08-09T23:46:27-07:00","committed_date":"2012-08-09T23:46:27-07:00"}},{"name":"refactoring","commit":{"id":"7c7761099cae83f59fe5780340e100be890847b2","parents":[{"id":"058d80b3363dd4fc4417ca4f60f76119188a2470"}],"tree":"d7d4a94c700dc0e84ee943019213d2358a49c413","message":"fix deprecation warnings","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-05-29T07:16:28-07:00","committed_date":"2012-05-29T07:16:28-07:00"}}] diff --git a/lib/gitlab-cli/spec/fixtures/comment_merge_request.json b/lib/gitlab-cli/spec/fixtures/comment_merge_request.json deleted file mode 100644 index 742f3337..00000000 --- a/lib/gitlab-cli/spec/fixtures/comment_merge_request.json +++ /dev/null @@ -1 +0,0 @@ -{"note":"Cool Merge Request!","author":{"id":1,"username":"jsmith","email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-07-11T01:32:18Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/create_branch.json b/lib/gitlab-cli/spec/fixtures/create_branch.json deleted file mode 100644 index a24df91a..00000000 --- a/lib/gitlab-cli/spec/fixtures/create_branch.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"api","commit":{ "id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","message":"API: expose issues project id","parent_ids":["949b1df930bedace1dbd755aaa4a82e8c451a616"],"authored_date":"2012-07-25T04:22:21-07:00","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","committed_date":"2012-07-25T04:22:21-07:00","committer_name":"Nihad Abbasov","committer_email":"narkoz.2008@gmail.com"},"protected": false} diff --git a/lib/gitlab-cli/spec/fixtures/create_merge_request.json b/lib/gitlab-cli/spec/fixtures/create_merge_request.json deleted file mode 100644 index c2743516..00000000 --- a/lib/gitlab-cli/spec/fixtures/create_merge_request.json +++ /dev/null @@ -1 +0,0 @@ -{"id":2,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/error_already_exists.json b/lib/gitlab-cli/spec/fixtures/error_already_exists.json deleted file mode 100644 index d1070f56..00000000 --- a/lib/gitlab-cli/spec/fixtures/error_already_exists.json +++ /dev/null @@ -1 +0,0 @@ -{"message": "409 Already exists"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group.json b/lib/gitlab-cli/spec/fixtures/group.json deleted file mode 100644 index 16620ad6..00000000 --- a/lib/gitlab-cli/spec/fixtures/group.json +++ /dev/null @@ -1,60 +0,0 @@ -{"id": 10, "name": "GitLab-Group", "path": "gitlab-group", "owner_id": 6, "projects": [ - { - "id": 9, - "name": "mojito", - "description": null, - "default_branch": "master", - "owner": { - "id": 6, - "username": "jose", - "email": "jose@abc.com", - "name": "Jose Jose", - "blocked": false, - "created_at": "2013-02-06T06:54:06Z" - }, - "path": "mojito", - "path_with_namespace": "gitlab-group/mojito", - "issues_enabled": true, - "merge_requests_enabled": true, - "wall_enabled": true, - "wiki_enabled": true, - "created_at": "2013-02-06T16:59:15Z", - "namespace": { - "created_at": "2013-02-06T16:58:22Z", - "id": 10, - "name": "GitLab-Group", - "owner_id": 6, - "path": "gitlab-group", - "updated_at": "2013-02-06T16:58:22Z" - } - }, - { - "id": 10, - "name": "gitlabhq", - "description": null, - "default_branch": null, - "owner": { - "id": 6, - "username": "randx", - "email": "randx@github.com", - "name": "Dmitry Z", - "blocked": false, - "created_at": "2013-02-06T06:54:06Z" - }, - "path": "gitlabhq", - "path_with_namespace": "gitlab-group/gitlabhq", - "issues_enabled": true, - "merge_requests_enabled": true, - "wall_enabled": true, - "wiki_enabled": true, - "created_at": "2013-02-06T17:02:31Z", - "namespace": { - "created_at": "2013-02-06T16:58:22Z", - "id": 10, - "name": "GitLab-Group", - "owner_id": 6, - "path": "gitlab-group", - "updated_at": "2013-02-06T16:58:22Z" - } - } -]} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_create.json b/lib/gitlab-cli/spec/fixtures/group_create.json deleted file mode 100644 index 67445f68..00000000 --- a/lib/gitlab-cli/spec/fixtures/group_create.json +++ /dev/null @@ -1 +0,0 @@ -{"id":3,"name":"Gitlab-Group","path":"gitlab-group","owner_id":1} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_member.json b/lib/gitlab-cli/spec/fixtures/group_member.json deleted file mode 100644 index feef5432..00000000 --- a/lib/gitlab-cli/spec/fixtures/group_member.json +++ /dev/null @@ -1 +0,0 @@ -{"id":2,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-09-04T18:15:30Z","access_level":10} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_member_delete.json b/lib/gitlab-cli/spec/fixtures/group_member_delete.json deleted file mode 100644 index ff052edf..00000000 --- a/lib/gitlab-cli/spec/fixtures/group_member_delete.json +++ /dev/null @@ -1 +0,0 @@ -{"created_at":"2013-09-04T18:18:15Z","group_access":10,"group_id":3,"id":2,"notification_level":3,"updated_at":"2013-09-04T18:18:15Z","user_id":2} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_members.json b/lib/gitlab-cli/spec/fixtures/group_members.json deleted file mode 100644 index 02ddc108..00000000 --- a/lib/gitlab-cli/spec/fixtures/group_members.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1,"username":"eraymond","email":"eraymond@local.host","name":"Edward Raymond","state":"active","created_at":"2013-08-30T16:16:22Z","access_level":50},{"id":1,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-08-30T16:16:22Z","access_level":50}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/groups.json b/lib/gitlab-cli/spec/fixtures/groups.json deleted file mode 100644 index 5811774a..00000000 --- a/lib/gitlab-cli/spec/fixtures/groups.json +++ /dev/null @@ -1,2 +0,0 @@ -[{"id": 3,"name": "ThreeGroup","path": "threegroup","owner_id": 1},{"id": 5,"name": "Five-Group","path": "five-group","owner_id": 2},{"id": 8,"name": "Eight Group","path": "eight-group","owner_id": 6} -] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/issue.json b/lib/gitlab-cli/spec/fixtures/issue.json deleted file mode 100644 index 9f70318a..00000000 --- a/lib/gitlab-cli/spec/fixtures/issue.json +++ /dev/null @@ -1 +0,0 @@ -{"id":33,"project_id":3,"title":"Beatae possimus nostrum nihil reiciendis laboriosam nihil delectus alias accusantium dolor unde.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/issues.json b/lib/gitlab-cli/spec/fixtures/issues.json deleted file mode 100644 index 62e4cadd..00000000 --- a/lib/gitlab-cli/spec/fixtures/issues.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1,"project_id":1,"title":"Culpa eius recusandae suscipit autem distinctio dolorum.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":6,"project_id":2,"title":"Ut in dolorum omnis sed sit aliquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":12,"project_id":3,"title":"Veniam et tempore quidem eum reprehenderit cupiditate non aut velit eaque.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":21,"project_id":1,"title":"Vitae ea aliquam et quo eligendi sapiente voluptatum labore hic nihil culpa.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":26,"project_id":2,"title":"Quo enim est nihil atque placeat voluptas neque eos voluptas.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":32,"project_id":3,"title":"Deserunt tenetur impedit est beatae voluptas voluptas quaerat quisquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/key.json b/lib/gitlab-cli/spec/fixtures/key.json deleted file mode 100644 index cd21098c..00000000 --- a/lib/gitlab-cli/spec/fixtures/key.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1,"title":"narkoz@helium","key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkUsh42Nh1yefGd1jbSELn5XsY8p5Oxmau0/1HqHnjuYOaj5X+kHccFDwtmtg9Ox8ua/+WptNsiE8IUwsD3zKgEjajgwq3gMeeFdxfXwM+tEvHOOMV9meRrgRWGYCToPbT6sR7/YMAYa7cPqWSpx/oZhYfz4XtoMv3ZZT1fZMmx3MY3HwXwW8j+obJyN2K4LN0TFi9RPgWWYn0DCyb9OccmABimt3i74WoJ/OT8r6/7swce8+OSe0Q2wBhyTtvxg2vtUcoek8Af+EZaUMBwSEzEsocOCzwQvjF5XUk5o7dJ8nP8W3RE60JWX57t16eQm7lBmumLYfszpn2isd6W7a1 narkoz@helium"} diff --git a/lib/gitlab-cli/spec/fixtures/keys.json b/lib/gitlab-cli/spec/fixtures/keys.json deleted file mode 100644 index db3bbea8..00000000 --- a/lib/gitlab-cli/spec/fixtures/keys.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1,"title":"narkoz@helium","key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkUsh42Nh1yefGd1jbSELn5XsY8p5Oxmau0/1HqHnjuYOaj5X+kHccFDwtmtg9Ox8ua/+WptNsiE8IUwsD3zKgEjajgwq3gMeeFdxfXwM+tEvHOOMV9meRrgRWGYCToPbT6sR7/YMAYa7cPqWSpx/oZhYfz4XtoMv3ZZT1fZMmx3MY3HwXwW8j+obJyN2K4LN0TFi9RPgWWYn0DCyb9OccmABimt3i74WoJ/OT8r6/7swce8+OSe0Q2wBhyTtvxg2vtUcoek8Af+EZaUMBwSEzEsocOCzwQvjF5XUk5o7dJ8nP8W3RE60JWX57t16eQm7lBmumLYfszpn2isd6W7a1 narkoz@helium"}] diff --git a/lib/gitlab-cli/spec/fixtures/merge_request.json b/lib/gitlab-cli/spec/fixtures/merge_request.json deleted file mode 100644 index 5278f466..00000000 --- a/lib/gitlab-cli/spec/fixtures/merge_request.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/merge_request_comments.json b/lib/gitlab-cli/spec/fixtures/merge_request_comments.json deleted file mode 100644 index 4e507668..00000000 --- a/lib/gitlab-cli/spec/fixtures/merge_request_comments.json +++ /dev/null @@ -1 +0,0 @@ -[{"note":"this is the 1st comment on the 2merge merge request","author":{"id":11,"username":"admin","email":"admin@example.com","name":"A User","state":"active","created_at":"2014-03-06T08:17:35.000Z"}},{"note":"another discussion point on the 2merge request","author":{"id":12,"username":"admin","email":"admin@example.com","name":"A User","state":"active","created_at":"2014-03-06T08:17:35.000Z"}}] diff --git a/lib/gitlab-cli/spec/fixtures/merge_requests.json b/lib/gitlab-cli/spec/fixtures/merge_requests.json deleted file mode 100644 index 33153c0c..00000000 --- a/lib/gitlab-cli/spec/fixtures/merge_requests.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}}] diff --git a/lib/gitlab-cli/spec/fixtures/milestone.json b/lib/gitlab-cli/spec/fixtures/milestone.json deleted file mode 100644 index 94ea3d36..00000000 --- a/lib/gitlab-cli/spec/fixtures/milestone.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1,"project_id":3,"title":"3.0","description":"","due_date":"2012-10-22","closed":false,"updated_at":"2012-09-17T10:15:31Z","created_at":"2012-09-17T10:15:31Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/milestones.json b/lib/gitlab-cli/spec/fixtures/milestones.json deleted file mode 100644 index f9e309af..00000000 --- a/lib/gitlab-cli/spec/fixtures/milestones.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1,"project_id":3,"title":"3.0","description":"","due_date":"2012-10-22","closed":false,"updated_at":"2012-09-17T10:15:31Z","created_at":"2012-09-17T10:15:31Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/note.json b/lib/gitlab-cli/spec/fixtures/note.json deleted file mode 100644 index 9cff9072..00000000 --- a/lib/gitlab-cli/spec/fixtures/note.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1201,"body":"The solution is rather tricky","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"created_at":"2012-11-27T19:16:44Z"} diff --git a/lib/gitlab-cli/spec/fixtures/notes.json b/lib/gitlab-cli/spec/fixtures/notes.json deleted file mode 100644 index e8fa27bf..00000000 --- a/lib/gitlab-cli/spec/fixtures/notes.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1201,"body":"The solution is rather tricky","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"created_at":"2012-11-27T19:16:44Z"},{"id":1207,"body":"I know, right?","author":{"id":1,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"created_at":"2012-11-27T19:58:21Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/project.json b/lib/gitlab-cli/spec/fixtures/project.json deleted file mode 100644 index 1f4f9602..00000000 --- a/lib/gitlab-cli/spec/fixtures/project.json +++ /dev/null @@ -1 +0,0 @@ -{"id":3,"code":"gitlab","name":"Gitlab","description":null,"path":"gitlab","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"public":false,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:58Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_commit.json b/lib/gitlab-cli/spec/fixtures/project_commit.json deleted file mode 100644 index ab29f6b7..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_commit.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", - "short_id": "6104942438c", - "title": "Sanitize for network graph", - "author_name": "randx", - "author_email": "dmitriy.zaporozhets@gmail.com", - "created_at": "2012-09-20T09:06:12+03:00", - "committed_date": "2012-09-20T09:06:12+03:00", - "authored_date": "2012-09-20T09:06:12+03:00", - "parent_ids": [ - "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" - ] -} diff --git a/lib/gitlab-cli/spec/fixtures/project_commit_diff.json b/lib/gitlab-cli/spec/fixtures/project_commit_diff.json deleted file mode 100644 index 1c3ce017..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_commit_diff.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files", - "new_path": "doc/update/5.4-to-6.0.md", - "old_path": "doc/update/5.4-to-6.0.md", - "a_mode": null, - "b_mode": "100644", - "new_file": false, - "renamed_file": false, - "deleted_file": false -} diff --git a/lib/gitlab-cli/spec/fixtures/project_commits.json b/lib/gitlab-cli/spec/fixtures/project_commits.json deleted file mode 100644 index 58cb5020..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_commits.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","short_id":"f7dd067490f","title":"API: expose issues project id","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T04:22:21-07:00"},{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616","short_id":"949b1df930b","title":"API: update docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T02:35:41-07:00"},{"id":"1b95c8bff351f6718ec31ac1de1e48c57bc95d44","short_id":"1b95c8bff35","title":"API: ability to get project by id","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T02:18:30-07:00"},{"id":"92d98f5a0c28bffd7b070cda190b07ab72667d58","short_id":"92d98f5a0c2","title":"Merge pull request #1118 from patthoyts/pt/ldap-missing-password","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:51:06-07:00"},{"id":"60d3e94874964a626f105d3598e1c122addcf43e","short_id":"60d3e948749","title":"Merge pull request #1122 from patthoyts/pt/missing-log","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:50:34-07:00"},{"id":"b683a71aa1230f17f9df47661c77dfeae27027de","short_id":"b683a71aa12","title":"Merge pull request #1135 from NARKOZ/api","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:48:00-07:00"},{"id":"fbb41100db35cf2def2c8b4d896b7015d56bd15b","short_id":"fbb41100db3","title":"update help section with issues API docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:52:43-07:00"},{"id":"eca823c1c7cef45cc18c6ab36d2327650c85bfc3","short_id":"eca823c1c7c","title":"Merge branch 'master' into api","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:46:36-07:00"},{"id":"024e0348904179a8dea81c01e27a5f014cf57499","short_id":"024e0348904","title":"update API docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:25:01-07:00"},{"id":"7b33d8cbcab3b0ee5789ec607455ab62130db69f","short_id":"7b33d8cbcab","title":"add issues API","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:19:51-07:00"},{"id":"6035ad7e1fe519d0c6a42731790183889e3ba31d","short_id":"6035ad7e1fe","title":"Create the githost.log file if necessary.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-21T07:32:04-07:00"},{"id":"a2d244ec062f3348f6cd1c5218c6097402c5f562","short_id":"a2d244ec062","title":"Handle LDAP missing credentials error with a flash message.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-21T01:04:05-07:00"},{"id":"8b7e404b5b6944e9c92cc270b2e5d0005781d49d","short_id":"8b7e404b5b6","title":"Up to 2.7.0","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:53:55-07:00"},{"id":"11721b0dbe82c35789be3e4fa8e14663934b2ff5","short_id":"11721b0dbe8","title":"Help section for system hooks completed","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:47:57-07:00"},{"id":"9c8a1e651716212cf50a623d98e03b8dbdb2c64a","short_id":"9c8a1e65171","title":"Fix system hook example","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:32:42-07:00"},{"id":"4261acda90ff4c61326d80cba026ae76e8551f8f","short_id":"4261acda90f","title":"move SSH keys tab closer to begining","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:27:09-07:00"},{"id":"a69fc5dd23bd502fd36892a80eec21a4c53891f8","short_id":"a69fc5dd23b","title":"Endless event loading for dsahboard","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:23:05-07:00"},{"id":"860fa1163a5fbdfec2bb01ff2d584351554dee29","short_id":"860fa1163a5","title":"Merge pull request #1117 from patthoyts/pt/user-form","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-20T14:23:49-07:00"},{"id":"787e5e94acf5e20280416c9fda105ef5b77576b3","short_id":"787e5e94acf","title":"Fix english on the edit user form.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-20T14:18:42-07:00"},{"id":"9267cb04b0b3fdf127899c4b7e636dc27fac06d3","short_id":"9267cb04b0b","title":"Merge branch 'refactoring_controllers' of dev.gitlabhq.com:gitlabhq","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-20T07:24:56-07:00"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_delete_key.json b/lib/gitlab-cli/spec/fixtures/project_delete_key.json deleted file mode 100644 index 9ff86833..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_delete_key.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "created_at": "2013-10-05T15:05:26Z", - "fingerprint": "5c:b5:e6:b0:f5:31:65:3f:a6:b5:59:86:32:cc:15:e1", - "id": 2, - "key": "ssh-rsa ...", - "updated_at": "2013-10-05T15:05:26Z", - "user_id": null -} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_events.json b/lib/gitlab-cli/spec/fixtures/project_events.json deleted file mode 100644 index e9fa22fe..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_events.json +++ /dev/null @@ -1 +0,0 @@ -[{"title":null,"project_id":2,"action_name":"opened","target_id":null,"target_type":null,"author_id":1,"data":{"before":"ac0c1aa3898d6dea54d7868ea6f9c45fd5e30c59","after":"66350dbb62a221bc619b665aef3e1e7d3b306747","ref":"refs/heads/master","user_id":1,"user_name":"Administrator","project_id":2,"repository":{"name":"gitlab-ci","url":"git@demo.gitlab.com:gitlab/gitlab-ci.git","description":"Continuous integration server for gitlabhq | Coordinator","homepage":"http://demo.gitlab.com/gitlab/gitlab-ci"},"commits":[{"id":"8cf469b039931bab37bbf025e6b69287ea3cfb0e","message":"Modify screenshot\n\nSigned-off-by: Dmitriy Zaporozhets \u003Cdummy@gmail.com\u003E","timestamp":"2014-05-20T10:34:27+00:00","url":"http://demo.gitlab.com/gitlab/gitlab-ci/commit/8cf469b039931bab37bbf025e6b69287ea3cfb0e","author":{"name":"Dummy","email":"dummy@gmail.com"}},{"id":"66350dbb62a221bc619b665aef3e1e7d3b306747","message":"Edit some code\n\nSigned-off-by: Dmitriy Zaporozhets \u003Cdummy@gmail.com\u003E","timestamp":"2014-05-20T10:35:15+00:00","url":"http://demo.gitlab.com/gitlab/gitlab-ci/commit/66350dbb62a221bc619b665aef3e1e7d3b306747","author":{"name":"Dummy","email":"dummy@gmail.com"}}],"total_commits_count":2},"target_title":null,"created_at":"2014-05-20T10:35:26.240Z"},{"title":null,"project_id":2,"action_name":"opened","target_id":2,"target_type":"MergeRequest","author_id":1,"data":null,"target_title":" Morbi et cursus leo. Sed eget vestibulum sapien","created_at":"2014-05-20T10:24:11.917Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/project_for_user.json b/lib/gitlab-cli/spec/fixtures/project_for_user.json deleted file mode 100644 index 5ffc888f..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_for_user.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1,"code":"brute","name":"Brute","description":null,"path":"brute","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Owner","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:56Z"} diff --git a/lib/gitlab-cli/spec/fixtures/project_fork_link.json b/lib/gitlab-cli/spec/fixtures/project_fork_link.json deleted file mode 100644 index f1490dfa..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_fork_link.json +++ /dev/null @@ -1 +0,0 @@ -{"created_at":"2013-07-03T13:51:48Z","forked_from_project_id":24,"forked_to_project_id":42,"id":1,"updated_at":"2013-07-03T13:51:48Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_hook.json b/lib/gitlab-cli/spec/fixtures/project_hook.json deleted file mode 100644 index 323741cf..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_hook.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1,"url":"https://api.example.net/v1/webhooks/ci"} diff --git a/lib/gitlab-cli/spec/fixtures/project_hooks.json b/lib/gitlab-cli/spec/fixtures/project_hooks.json deleted file mode 100644 index e70d4122..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_hooks.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1,"url":"https://api.example.net/v1/webhooks/ci"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_issues.json b/lib/gitlab-cli/spec/fixtures/project_issues.json deleted file mode 100644 index 87fb2fb1..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_issues.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":36,"project_id":3,"title":"Eos ut modi et laudantium quasi porro voluptas sed.","description":null,"labels":[],"milestone":null,"assignee":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":35,"project_id":3,"title":"Ducimus illo in iure voluptatem dolores labore.","description":null,"labels":[],"milestone":null,"assignee":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":34,"project_id":3,"title":"Rem tempora voluptatum atque eum sit nihil neque.","description":null,"labels":[],"milestone":null,"assignee":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":33,"project_id":3,"title":"Beatae possimus nostrum nihil reiciendis laboriosam nihil delectus alias accusantium dolor unde.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":32,"project_id":3,"title":"Deserunt tenetur impedit est beatae voluptas voluptas quaerat quisquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":16,"project_id":3,"title":"Numquam earum aut laudantium reprehenderit voluptatem aut.","description":null,"labels":[],"milestone":null,"assignee":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":15,"project_id":3,"title":"Qui veritatis voluptas fuga voluptate voluptas cupiditate.","description":null,"labels":[],"milestone":null,"assignee":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":14,"project_id":3,"title":"In assumenda et ipsa qui debitis voluptatem incidunt.","description":null,"labels":[],"milestone":null,"assignee":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":13,"project_id":3,"title":"Illo eveniet consequatur enim iste provident facilis rerum voluptatem et architecto aut.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":12,"project_id":3,"title":"Veniam et tempore quidem eum reprehenderit cupiditate non aut velit eaque.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_key.json b/lib/gitlab-cli/spec/fixtures/project_key.json deleted file mode 100644 index 6dd70d23..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_key.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": 2, - "title": "Key Title", - "key": "ssh-rsa ...", - "created_at": "2013-09-22T18:34:32Z" -} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_keys.json b/lib/gitlab-cli/spec/fixtures/project_keys.json deleted file mode 100644 index 0a3869d3..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_keys.json +++ /dev/null @@ -1,6 +0,0 @@ -[{ - "id": 2, - "title": "Key Title", - "key": "ssh-rsa ...", - "created_at": "2013-09-22T18:34:32Z" -}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_tags.json b/lib/gitlab-cli/spec/fixtures/project_tags.json deleted file mode 100644 index 1e2fb96c..00000000 --- a/lib/gitlab-cli/spec/fixtures/project_tags.json +++ /dev/null @@ -1 +0,0 @@ -[{"name":"v2.8.2","commit":{"id":"a502f67c0b358cc6b391df0c5dca48375c21fcad","parents":[{"id":"4381084af341684240b1a671d368511afcf5774a"}],"tree":"1612068bdd20de5d14b3096cfa4c621e2051ed4c","message":"Up to 2.8.2","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-24T02:03:48-07:00","committed_date":"2012-08-24T02:03:48-07:00"}},{"name":"v2.8.1","commit":{"id":"ed2b53cd1c34c421b23208eeb502a141a6829f9d","parents":[{"id":"7ab587a47791e371f5c109c14097a5d1d7776ea5"}],"tree":"b7393b0b33b777583b285e85b423c4e5ab7f859f","message":"Up to 2.8.1","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-22T23:17:18-07:00","committed_date":"2012-08-22T23:17:18-07:00"}},{"name":"v2.8.0pre","commit":{"id":"b2c6ba97a25d299e83c51493d7bc770c13b8ed1a","parents":[{"id":"05da3801f53f06fdc529b4f3820af1380039f245"},{"id":"66399d558da45fb9cd3ea972a47a4f7bb12bfc8d"}],"tree":"36ad53f35bce1fe3f2a4a5f840e7b1bdbfed9c82","message":"Merge pull request #1230 from tsigo/hooray_apostrophes\n\nCorrect usage of \"Can't\"","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-16T14:11:08-07:00","committed_date":"2012-08-16T14:11:08-07:00"}},{"name":"v2.8.0","commit":{"id":"5c7ed6fa26b47ac71ff6ba04720d85df6d74b200","parents":[{"id":"d1daeba1736ba145fe525ce08a91f29495a3abf1"}],"tree":"4fc230ff2dbc0e75f27321eac2976aba5a6d323d","message":"Up to 2.8","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-21T15:15:26-07:00","committed_date":"2012-08-21T15:15:26-07:00"}},{"name":"v2.7.0pre","commit":{"id":"72a571724d84d112f98a5543c971e9b3b9da1383","parents":[{"id":"3ac840ff06e0ee5b349c52b5a8c02e803a17eec3"},{"id":"990b9217d9a55e26a53d4143d4a3c89123384327"}],"tree":"64b104df5d956e21e0749dc8e70849d1989de36f","message":"Merge pull request #1096 from moregeek/show-flash-note-when-destroying-a-project\n\nshow flash notice after deletion of a project","author":{"name":"Valeriy Sizov","email":"vsv2711@gmail.com"},"committer":{"name":"Valeriy Sizov","email":"vsv2711@gmail.com"},"authored_date":"2012-07-18T05:35:42-07:00","committed_date":"2012-07-18T05:35:42-07:00"}},{"name":"v2.7.0","commit":{"id":"8b7e404b5b6944e9c92cc270b2e5d0005781d49d","parents":[{"id":"11721b0dbe82c35789be3e4fa8e14663934b2ff5"}],"tree":"89fe8c5ff58daaedea07a910cffb14b04ebcc828","message":"Up to 2.7.0","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-07-21T00:53:55-07:00","committed_date":"2012-07-21T00:53:55-07:00"}},{"name":"v2.6.3","commit":{"id":"666cdb22792dd955a286b9993d6235b4cdd68b4b","parents":[{"id":"d92446df1fdba87101c92c90b1c34eb2f1eebef4"}],"tree":"888173aa4c12a4920d318c35b950095d3505673d","message":"up to 2.6.3","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-26T09:20:47-07:00","committed_date":"2012-06-26T09:21:28-07:00"}},{"name":"v2.6.2","commit":{"id":"39fecb554f172a0c8ea00316e612e1d37efc7200","parents":[{"id":"68389588d664100590b1a6ca7eedd50860b7e9bc"}],"tree":"53accb25e0b9d038d550cf387753bde15fe4ad19","message":"Up to 2.6.2","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-22T13:50:58-07:00","committed_date":"2012-06-22T13:50:58-07:00"}},{"name":"v2.6.1","commit":{"id":"d92a22c9e627268eca697bbd9b660d8c335df953","parents":[{"id":"193804516b8b0783c850981456e947f888ff51bb"}],"tree":"4ac1b5225f597ab55372cb5e950b121d6f55e386","message":"Up to 2.6.1","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-22T12:49:03-07:00","committed_date":"2012-06-22T12:49:03-07:00"}},{"name":"v2.6.0","commit":{"id":"b32465712becfbcf83d63b1e6eff7d1483fdabea","parents":[{"id":"1903f6ade027df0f10ef96b9439495eeda07482c"}],"tree":"ffbc05fd0f1771c1602c956df9556260048c7167","message":"Up to 2.6","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-21T10:25:23-07:00","committed_date":"2012-06-21T10:25:23-07:00"}},{"name":"v2.5.0","commit":{"id":"cc8369144db2147d2956e8dd7d314e9a7dfd4fbb","parents":[{"id":"1b2068eaa91e5002d01a220c65da21dad8ccb071"}],"tree":"666a442e00689911169e8cc336c5ce60d014854c","message":"Prevent app crash in case if encoding failed","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-05-22T04:57:04-07:00","committed_date":"2012-05-22T04:57:04-07:00"}},{"name":"v2.4.2","commit":{"id":"f18339c26d673c5f8b4c19776036fd42a0de30aa","parents":[{"id":"c937d06c3c98e9ffce8ec1132203eaff6bf7b231"},{"id":"35e602f19c83585d64aa2043ed26eeb8cd7b40e2"}],"tree":"5101f0cd8e395fee1996764298a202437757e85b","message":"Merge branch 'master' of github.com:gitlabhq/gitlabhq","author":{"name":"Zevs","email":"vsv2711@gmail.com"},"committer":{"name":"Zevs","email":"vsv2711@gmail.com"},"authored_date":"2012-04-29T14:24:59-07:00","committed_date":"2012-04-29T14:24:59-07:00"}},{"name":"v2.4.1","commit":{"id":"d97a9aa4a44ff9f452144fad348fd9d7e3b48260","parents":[{"id":"21f3da23589d50038728393f0badc6255b5762ca"}],"tree":"905c33874b064778199f806749d5688e33d64be3","message":"fixed email markdown","author":{"name":"gitlabhq","email":"m@gitlabhq.com"},"committer":{"name":"gitlabhq","email":"m@gitlabhq.com"},"authored_date":"2012-04-23T05:32:56-07:00","committed_date":"2012-04-23T05:32:56-07:00"}},{"name":"v2.4.0pre","commit":{"id":"1845429268364e75bffdeb1075de8f1606e157ec","parents":[{"id":"45b18365d5f409f196a02a4e6e2b77b8ebef909b"}],"tree":"423c70246fa7ffd8804b26628fea34bdb2b22846","message":"Use try for commit prev_commit_id detection","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-04-19T13:35:35-07:00","committed_date":"2012-04-19T13:35:35-07:00"}},{"name":"v2.4.0","commit":{"id":"204c66461ed519eb0078be7e8ac8a6cb56834753","parents":[{"id":"511d07c47c9bf3a18bfa276d452c899369432a22"}],"tree":"9416c777cccf87d348f5705078e82f3f97485e19","message":"corrected exception for automerge","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-04-22T06:49:45-07:00","committed_date":"2012-04-22T06:49:45-07:00"}},{"name":"v2.3.1","commit":{"id":"fa8219e0a753e642a6f1dbdfc010d01ae8a949ee","parents":[{"id":"81da8e46f24913ccf42d3e2644962cbcbc0f9c2e"}],"tree":"5debfcd6d17f9d582aace6ac9b80db27d5c1fe36","message":"better MR list, dashboard pollished","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-22T13:57:04-07:00","committed_date":"2012-03-22T13:57:04-07:00"}},{"name":"v2.3.0pre","commit":{"id":"cadf12c60cc27c5b0b8273c1de4b190a0e88bd7d","parents":[{"id":"724ea16c348bc61cf7cb3dbe362c6f30cff1b2c7"}],"tree":"6f4c22761fd2dee405d3fbf38f9dd835bb3c8694","message":"Merged activities & projects pages","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-19T15:05:35-07:00","committed_date":"2012-03-19T15:05:35-07:00"}},{"name":"v2.3.0","commit":{"id":"b57faf9282d7df6cdd62953d474652a0ae2e6896","parents":[{"id":"cadf12c60cc27c5b0b8273c1de4b190a0e88bd7d"}],"tree":"f0d5b826df373191b4681452fc2ae4c5970cef4a","message":"Push events polished","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-20T14:59:35-07:00","committed_date":"2012-03-20T14:59:35-07:00"}},{"name":"v2.2.0pre","commit":{"id":"6a445b42003007cbb6c06f477c4d7a0b175688c1","parents":[{"id":"22f4c1908d0fc2dbce02e74ed03bf65f028d78d6"}],"tree":"9c60577833f6ca717acdebfa66140124c88e8471","message":"fixed forgot password form","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-02-20T10:37:37-08:00","committed_date":"2012-02-20T10:37:37-08:00"}},{"name":"v2.2.0","commit":{"id":"9e6d0710e927aa8ea834b8a9ae9f277be617ac7d","parents":[{"id":"8c40aab120dbc5507ab9cc8d7ad8e2519d6e9f25"},{"id":"6ea87c47f0f8a24ae031c3fff17bc913889ecd00"}],"tree":"86c831ab21236f21ffa5b97c752369612ce41b39","message":"Merge pull request #443 from CedricGatay/fix/incorrectLineNumberingInDiff\n\nIncorrect line numbering in diff","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-02-22T07:14:54-08:00","committed_date":"2012-02-22T07:14:54-08:00"}},{"name":"v2.1.0","commit":{"id":"98d6492582d232ed86525aa31ccbf280f4cbdaef","parents":[{"id":"611c5a87ab0c083a43785323b09cc47f554c3ba4"}],"tree":"1689b3cad580a18fd9b429ee0b33dac21c9f5a48","message":"removed broken migration","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-01-22T10:52:06-08:00","committed_date":"2012-01-22T10:52:06-08:00"}},{"name":"v2.0.0","commit":{"id":"9a2a8612769d472503b367fa35e99f6fb2876704","parents":[{"id":"2f7b67161952fc9ab322eba6878511b5f2dd5cf1"}],"tree":"26cdb4e66b5e664fe4bcd57d011c54c9c9c26ded","message":"Design tab for profile. Colorscheme as db value","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2011-12-20T12:47:09-08:00","committed_date":"2011-12-20T12:47:09-08:00"}},{"name":"v1.2.2","commit":{"id":"139a332293b9d8c4e5436619036e093483d8347f","parents":[{"id":"ade12da9488bea19d12505c371ead35686a1436e"}],"tree":"365d57f4df5c5dcac69b666cf6d2bfd8ef058008","message":"updated readme","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-25T14:30:51-08:00","committed_date":"2011-11-25T14:30:51-08:00"}},{"name":"v1.2.1","commit":{"id":"7ebba27db21719c0035bab65fea92a4780051c73","parents":[{"id":"b56024100d40457a998f83adae3cdc830c997cda"},{"id":"a4fbe13fce87cb6ff2a27a2574ae25bf1dad145c"}],"tree":"b121a7576af1503a96954ce9a94598a68579e053","message":"Merge branch 'master' of dev.gitlabhq.com:gitlabhq","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-22T13:15:09-08:00","committed_date":"2011-11-22T13:15:09-08:00"}},{"name":"v1.2.0pre","commit":{"id":"86829cae50857b5edf74b935380c6f68a19c2282","parents":[{"id":"a6b99319381c2d62ec4b92d64805e8de8965859e"}],"tree":"6aab9d13000584fa96fb3cb34d94f3b122bd1143","message":"fixed min height for menu","author":{"name":"gitlabhq","email":"m@gitlabhq.com"},"committer":{"name":"gitlabhq","email":"m@gitlabhq.com"},"authored_date":"2011-11-22T06:03:27-08:00","committed_date":"2011-11-22T06:03:27-08:00"}},{"name":"v1.2.0","commit":{"id":"b56024100d40457a998f83adae3cdc830c997cda","parents":[{"id":"4451b8df8ad6d4b6d79fbce77687c6c2fd37d0a9"}],"tree":"f402cbb6d54526a32b30968c98410bae97b27c8d","message":"lil style fixes","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-22T09:57:25-08:00","committed_date":"2011-11-22T09:57:25-08:00"}},{"name":"v1.1.0pre","commit":{"id":"6b030fd41d697e327d2935b406cba70b6a460504","parents":[{"id":"3a2b273316fb29d63b489906f85d9b5329377258"}],"tree":"63b1fdb2a0f135f7074f6a94da14543b8450dd71","message":"1.1pre1","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-21T10:04:41-07:00","committed_date":"2011-10-21T10:04:41-07:00"}},{"name":"v1.1.0","commit":{"id":"ba8048d71019b5aaa1f92ee5c3415bfddaa9babb","parents":[{"id":"6b030fd41d697e327d2935b406cba70b6a460504"}],"tree":"4db2b5f4f9b374dd1be3579459bc5947c225c9ba","message":"v1.1.0","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-22T06:07:26-07:00","committed_date":"2011-10-22T06:07:26-07:00"}},{"name":"v1.0.2","commit":{"id":"3a2b273316fb29d63b489906f85d9b5329377258","parents":[{"id":"757ea634665e475bf69c1ec962040a0511ee8aeb"},{"id":"c374eb80ff9fb71d37faffc15714bf98b632d3e5"}],"tree":"e0d8170e61a9468a7bb5d4e63305171ec1efa6bf","message":"Merge pull request #40 from vslinko/patch-1\n\nIncrease max key length. Some keys has comment after key string.","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2011-10-18T23:30:06-07:00","committed_date":"2011-10-18T23:30:06-07:00"}},{"name":"v1.0.1","commit":{"id":"7b5799a97998b68416f1b6233ce427135c99165a","parents":[{"id":"0541b3f3c5dcd291d144c83d9731c75ee811b4e0"},{"id":"7b67480c76db8b9a9ccdc80015cc500dc6d26892"}],"tree":"e052185e9dd72a1b1a04d59a5f9efbf3c0369601","message":"Merge branch '1x' of github.com:gitlabhq/gitlabhq into 1x","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-14T15:16:44-07:00","committed_date":"2011-10-14T15:16:44-07:00"}}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/projects.json b/lib/gitlab-cli/spec/fixtures/projects.json deleted file mode 100644 index deab4c5f..00000000 --- a/lib/gitlab-cli/spec/fixtures/projects.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1,"code":"brute","name":"Brute","description":null,"path":"brute","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:56Z"},{"id":2,"code":"mozart","name":"Mozart","description":null,"path":"mozart","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:57Z"},{"id":3,"code":"gitlab","name":"Gitlab","description":null,"path":"gitlab","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:58Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/protect_branch.json b/lib/gitlab-cli/spec/fixtures/protect_branch.json deleted file mode 100644 index f71ebd5d..00000000 --- a/lib/gitlab-cli/spec/fixtures/protect_branch.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected":true} diff --git a/lib/gitlab-cli/spec/fixtures/session.json b/lib/gitlab-cli/spec/fixtures/session.json deleted file mode 100644 index e4f5ba35..00000000 --- a/lib/gitlab-cli/spec/fixtures/session.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","private_token":"qEsq1pt6HJPaNciie3MG"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/snippet.json b/lib/gitlab-cli/spec/fixtures/snippet.json deleted file mode 100644 index 34e9d994..00000000 --- a/lib/gitlab-cli/spec/fixtures/snippet.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1,"title":"Rails Console ActionMailer","file_name":"mailer_test.rb","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"expires_at":"2012-09-24T00:00:00Z","updated_at":"2012-09-17T09:51:42Z","created_at":"2012-09-17T09:51:42Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/snippets.json b/lib/gitlab-cli/spec/fixtures/snippets.json deleted file mode 100644 index 106f88f3..00000000 --- a/lib/gitlab-cli/spec/fixtures/snippets.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1,"title":"Rails Console ActionMailer","file_name":"mailer_test.rb","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"expires_at":"2012-09-24T00:00:00Z","updated_at":"2012-09-17T09:51:42Z","created_at":"2012-09-17T09:51:42Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/system_hook.json b/lib/gitlab-cli/spec/fixtures/system_hook.json deleted file mode 100644 index e2f485be..00000000 --- a/lib/gitlab-cli/spec/fixtures/system_hook.json +++ /dev/null @@ -1 +0,0 @@ -{"id": 3, "url": "http://example.com/hook", "created_at": "2013-10-02T10:15:31Z"} diff --git a/lib/gitlab-cli/spec/fixtures/system_hook_test.json b/lib/gitlab-cli/spec/fixtures/system_hook_test.json deleted file mode 100644 index 2c104c62..00000000 --- a/lib/gitlab-cli/spec/fixtures/system_hook_test.json +++ /dev/null @@ -1 +0,0 @@ -{ "event_name": "project_create", "name": "Ruby", "path": "ruby", "project_id": 1, "owner_name": "Someone", "owner_email": "example@gitlabhq.com" } diff --git a/lib/gitlab-cli/spec/fixtures/system_hooks.json b/lib/gitlab-cli/spec/fixtures/system_hooks.json deleted file mode 100644 index 9c529e6f..00000000 --- a/lib/gitlab-cli/spec/fixtures/system_hooks.json +++ /dev/null @@ -1 +0,0 @@ -[{"id": 3, "url": "http://example.com/hook", "created_at": "2013-10-02T10:15:31Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/tag.json b/lib/gitlab-cli/spec/fixtures/tag.json deleted file mode 100644 index 74584bdf..00000000 --- a/lib/gitlab-cli/spec/fixtures/tag.json +++ /dev/null @@ -1 +0,0 @@ -{"name": "v1.0.0","commit": {"id": "2695effb5807a22ff3d138d593fd856244e155e7","parents": [],"message": "Initial commit","authored_date": "2012-05-28T04:42:42-07:00","author_name": "John Smith","author email": "john@example.com","committer_name": "Jack Smith","committed_date": "2012-05-28T04:42:42-07:00","committer_email": "jack@example.com"},"protected": false} diff --git a/lib/gitlab-cli/spec/fixtures/team_member.json b/lib/gitlab-cli/spec/fixtures/team_member.json deleted file mode 100644 index fd3ac385..00000000 --- a/lib/gitlab-cli/spec/fixtures/team_member.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","access_level":40} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/team_members.json b/lib/gitlab-cli/spec/fixtures/team_members.json deleted file mode 100644 index a2fe19e3..00000000 --- a/lib/gitlab-cli/spec/fixtures/team_members.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","access_level":40},{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":20},{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":6,"email":"faye.watsica@rohanwalter.com","name":"Ambrose Hansen","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":7,"email":"maida@walshtorp.name","name":"Alana Hahn","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":20}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/unprotect_branch.json b/lib/gitlab-cli/spec/fixtures/unprotect_branch.json deleted file mode 100644 index 307df403..00000000 --- a/lib/gitlab-cli/spec/fixtures/unprotect_branch.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected":false} diff --git a/lib/gitlab-cli/spec/fixtures/update_merge_request.json b/lib/gitlab-cli/spec/fixtures/update_merge_request.json deleted file mode 100644 index 735819ff..00000000 --- a/lib/gitlab-cli/spec/fixtures/update_merge_request.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"A different new feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/user.json b/lib/gitlab-cli/spec/fixtures/user.json deleted file mode 100644 index 4e0daca5..00000000 --- a/lib/gitlab-cli/spec/fixtures/user.json +++ /dev/null @@ -1 +0,0 @@ -{"id":1,"email":"john@example.com","name":"John Smith","bio":null,"skype":"","linkedin":"","twitter":"john","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:41:56Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/users.json b/lib/gitlab-cli/spec/fixtures/users.json deleted file mode 100644 index 14c6388b..00000000 --- a/lib/gitlab-cli/spec/fixtures/users.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":1,"email":"john@example.com","name":"John Smith","bio":null,"skype":"","linkedin":"","twitter":"john","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:41:56Z"},{"id":2,"email":"jack@example.com","name":"Jack Smith","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":6,"email":"faye.watsica@rohanwalter.com","name":"Ambrose Hansen","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":7,"email":"maida@walshtorp.name","name":"Alana Hahn","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/gitlab/cli_spec.rb b/lib/gitlab-cli/spec/gitlab/cli_spec.rb deleted file mode 100644 index a23139cb..00000000 --- a/lib/gitlab-cli/spec/gitlab/cli_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -require 'spec_helper' - -describe Gitlab::CLI do - describe ".run" do - context "when command is version" do - it "should show gem version" do - output = capture_output { Gitlab::CLI.run('-v') } - expect(output).to eq("Gitlab Ruby Gem #{Gitlab::VERSION}\n") - end - end - - context "when command is info" do - it "should show environment info" do - output = capture_output { Gitlab::CLI.run('info') } - expect(output).to include("Gitlab endpoint is") - expect(output).to include("Gitlab private token is") - expect(output).to include("Ruby Version is") - expect(output).to include("Gitlab Ruby Gem") - end - end - - context "when command is help" do - it "should show available actions" do - output = capture_output { Gitlab::CLI.run('help') } - expect(output).to include('Available commands') - expect(output).to include('MergeRequests') - expect(output).to include('team_members') - end - end - - context "when command is user" do - before do - stub_get("/user", "user") - @output = capture_output { Gitlab::CLI.run('user') } - end - - it "should show executed command" do - expect(@output).to include('Gitlab.user') - end - - it "should show user data" do - expect(@output).to include('name') - expect(@output).to include('John Smith') - end - end - end - - describe ".start" do - context "when command with excluded fields" do - before do - stub_get("/user", "user") - args = ['user', '--except=id,email,name'] - @output = capture_output { Gitlab::CLI.start(args) } - end - - it "should show user data with excluded fields" do - expect(@output).to_not include('John Smith') - expect(@output).to include('bio') - expect(@output).to include('created_at') - end - end - - context "when command with required fields" do - before do - stub_get("/user", "user") - args = ['user', '--only=id,email,name'] - @output = capture_output { Gitlab::CLI.start(args) } - end - - it "should show user data with required fields" do - expect(@output).to include('id') - expect(@output).to include('name') - expect(@output).to include('email') - expect(@output).to include('John Smith') - expect(@output).to_not include('bio') - expect(@output).to_not include('created_at') - end - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/client/branches_spec.rb b/lib/gitlab-cli/spec/gitlab/client/branches_spec.rb deleted file mode 100644 index 92c6a9a2..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/branches_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - it { should respond_to :repo_branches } - it { should respond_to :repo_branch } - it { should respond_to :repo_protect_branch } - it { should respond_to :repo_unprotect_branch } - - describe ".branches" do - before do - stub_get("/projects/3/repository/branches", "branches") - @branches = Gitlab.branches(3) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/repository/branches")).to have_been_made - end - - it "should return an array of repository branches" do - expect(@branches).to be_an Array - expect(@branches.first.name).to eq("api") - end - end - - describe ".branch" do - before do - stub_get("/projects/3/repository/branches/api", "branch") - @branch = Gitlab.branch(3, "api") - end - - it "should get the correct resource" do - expect(a_get("/projects/3/repository/branches/api")).to have_been_made - end - - it "should return information about a repository branch" do - expect(@branch.name).to eq("api") - end - end - - describe ".protect_branch" do - before do - stub_put("/projects/3/repository/branches/api/protect", "protect_branch") - @branch = Gitlab.protect_branch(3, "api") - end - - it "should get the correct resource" do - expect(a_put("/projects/3/repository/branches/api/protect")).to have_been_made - end - - it "should return information about a protected repository branch" do - expect(@branch.name).to eq("api") - expect(@branch.protected).to eq(true) - end - end - - describe ".unprotect_branch" do - before do - stub_put("/projects/3/repository/branches/api/unprotect", "unprotect_branch") - @branch = Gitlab.unprotect_branch(3, "api") - end - - it "should get the correct resource" do - expect(a_put("/projects/3/repository/branches/api/unprotect")).to have_been_made - end - - it "should return information about an unprotected repository branch" do - expect(@branch.name).to eq("api") - expect(@branch.protected).to eq(false) - end - end - - describe ".create_branch" do - context "with branch name" do - before do - stub_post("/projects/3/repository/branches", "create_branch") - @branch = Gitlab.create_branch(3, "api","master") - end - - it "should get the correct resource" do - expect(a_post("/projects/3/repository/branches")).to have_been_made - end - - it "should return information about a new repository branch" do - expect(@branch.name).to eq("api") - end - end - context "with commit hash" do - before do - stub_post("/projects/3/repository/branches", "create_branch") - @branch = Gitlab.create_branch(3, "api","949b1df930bedace1dbd755aaa4a82e8c451a616") - end - - it "should get the correct resource" do - expect(a_post("/projects/3/repository/branches")).to have_been_made - end - - it "should return information about a new repository branch" do - expect(@branch.name).to eq("api") - end - end - end - -end diff --git a/lib/gitlab-cli/spec/gitlab/client/groups_spec.rb b/lib/gitlab-cli/spec/gitlab/client/groups_spec.rb deleted file mode 100644 index 7336a3bd..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/groups_spec.rb +++ /dev/null @@ -1,111 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - describe ".groups" do - before do - stub_get("/groups", "groups") - stub_get("/groups/3", "group") - @group = Gitlab.group(3) - @groups = Gitlab.groups - end - - it "should get the correct resource" do - expect(a_get("/groups")).to have_been_made - expect(a_get("/groups/3")).to have_been_made - end - - it "should return an array of Groups" do - expect(@groups).to be_an Array - expect(@groups.first.path).to eq("threegroup") - end - end - - describe ".create_group" do - before do - stub_post("/groups", "group_create") - @group = Gitlab.create_group('GitLab-Group', 'gitlab-path') - end - - it "should get the correct resource" do - expect(a_post("/groups"). - with(:body => {:path => 'gitlab-path', :name => 'GitLab-Group'})).to have_been_made - end - - it "should return information about a created group" do - expect(@group.name).to eq("Gitlab-Group") - expect(@group.path).to eq("gitlab-group") - end - end - - describe ".transfer_project_to_group" do - before do - stub_post("/projects", "project") - @project = Gitlab.create_project('Gitlab') - stub_post("/groups", "group_create") - @group = Gitlab.create_group('GitLab-Group', 'gitlab-path') - - stub_post("/groups/#{@group.id}/projects/#{@project.id}", "group_create") - @group_transfer = Gitlab.transfer_project_to_group(@group.id,@project.id) - end - - it "should post to the correct resource" do - expect(a_post("/groups/#{@group.id}/projects/#{@project.id}").with(:body => {:id => @group.id.to_s, :project_id => @project.id.to_s})).to have_been_made - end - - it "should return information about the group" do - expect(@group_transfer.name).to eq(@group.name) - expect(@group_transfer.path).to eq(@group.path) - expect(@group_transfer.id).to eq(@group.id) - end - end - - describe ".group_members" do - before do - stub_get("/groups/3/members", "group_members") - @members = Gitlab.group_members(3) - end - - it "should get the correct resource" do - expect(a_get("/groups/3/members")).to have_been_made - end - - it "should return information about a group members" do - expect(@members).to be_an Array - expect(@members.size).to eq(2) - expect(@members[1].name).to eq("John Smith") - end - end - - describe ".add_group_member" do - before do - stub_post("/groups/3/members", "group_member") - @member = Gitlab.add_group_member(3, 1, 40) - end - - it "should get the correct resource" do - expect(a_post("/groups/3/members"). - with(:body => {:user_id => '1', :access_level => '40'})).to have_been_made - end - - it "should return information about an added member" do - expect(@member.name).to eq("John Smith") - end - end - - describe ".remove_group_member" do - before do - stub_delete("/groups/3/members/1", "group_member_delete") - @group = Gitlab.remove_group_member(3, 1) - end - - it "should get the correct resource" do - expect(a_delete("/groups/3/members/1")).to have_been_made - end - - it "should return information about the group the member was removed from" do - expect(@group.group_id).to eq(3) - end - end - - -end diff --git a/lib/gitlab-cli/spec/gitlab/client/issues_spec.rb b/lib/gitlab-cli/spec/gitlab/client/issues_spec.rb deleted file mode 100644 index 1a34699f..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/issues_spec.rb +++ /dev/null @@ -1,122 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - describe ".issues" do - context "with project ID passed" do - before do - stub_get("/projects/3/issues", "project_issues") - @issues = Gitlab.issues(3) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/issues")).to have_been_made - end - - it "should return an array of project's issues" do - expect(@issues).to be_an Array - expect(@issues.first.project_id).to eq(3) - end - end - - context "without project ID passed" do - before do - stub_get("/issues", "issues") - @issues = Gitlab.issues - end - - it "should get the correct resource" do - expect(a_get("/issues")).to have_been_made - end - - it "should return an array of user's issues" do - expect(@issues).to be_an Array - expect(@issues.first.closed).to be_falsey - expect(@issues.first.author.name).to eq("John Smith") - end - end - end - - describe ".issue" do - before do - stub_get("/projects/3/issues/33", "issue") - @issue = Gitlab.issue(3, 33) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/issues/33")).to have_been_made - end - - it "should return information about an issue" do - expect(@issue.project_id).to eq(3) - expect(@issue.assignee.name).to eq("Jack Smith") - end - end - - describe ".create_issue" do - before do - stub_post("/projects/3/issues", "issue") - @issue = Gitlab.create_issue(3, 'title') - end - - it "should get the correct resource" do - expect(a_post("/projects/3/issues"). - with(:body => {:title => 'title'})).to have_been_made - end - - it "should return information about a created issue" do - expect(@issue.project_id).to eq(3) - expect(@issue.assignee.name).to eq("Jack Smith") - end - end - - describe ".edit_issue" do - before do - stub_put("/projects/3/issues/33", "issue") - @issue = Gitlab.edit_issue(3, 33, :title => 'title') - end - - it "should get the correct resource" do - expect(a_put("/projects/3/issues/33"). - with(:body => {:title => 'title'})).to have_been_made - end - - it "should return information about an edited issue" do - expect(@issue.project_id).to eq(3) - expect(@issue.assignee.name).to eq("Jack Smith") - end - end - - describe ".close_issue" do - before do - stub_put("/projects/3/issues/33", "issue") - @issue = Gitlab.close_issue(3, 33) - end - - it "should get the correct resource" do - expect(a_put("/projects/3/issues/33"). - with(:body => {:state_event => 'close'})).to have_been_made - end - - it "should return information about an closed issue" do - expect(@issue.project_id).to eq(3) - expect(@issue.assignee.name).to eq("Jack Smith") - end - end - - describe ".reopen_issue" do - before do - stub_put("/projects/3/issues/33", "issue") - @issue = Gitlab.reopen_issue(3, 33) - end - - it "should get the correct resource" do - expect(a_put("/projects/3/issues/33"). - with(:body => {:state_event => 'reopen'})).to have_been_made - end - - it "should return information about an reopened issue" do - expect(@issue.project_id).to eq(3) - expect(@issue.assignee.name).to eq("Jack Smith") - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/client/merge_requests_spec.rb b/lib/gitlab-cli/spec/gitlab/client/merge_requests_spec.rb deleted file mode 100644 index 7c2253f7..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/merge_requests_spec.rb +++ /dev/null @@ -1,124 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - describe ".merge_requests" do - before do - stub_get("/projects/3/merge_requests", "merge_requests") - @merge_requests = Gitlab.merge_requests(3) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/merge_requests")).to have_been_made - end - - it "should return an array of project's merge requests" do - expect(@merge_requests).to be_an Array - expect(@merge_requests.first.project_id).to eq(3) - end - end - - describe ".merge_request" do - before do - stub_get("/projects/3/merge_request/1", "merge_request") - @merge_request = Gitlab.merge_request(3, 1) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/merge_request/1")).to have_been_made - end - - it "should return information about a merge request" do - expect(@merge_request.project_id).to eq(3) - expect(@merge_request.assignee.name).to eq("Jack Smith") - end - end - - describe ".create_merge_request" do - before do - stub_post("/projects/3/merge_requests", "create_merge_request") - end - - it "should fail if it doesn't have a source_branch" do - expect { - Gitlab.create_merge_request(3, 'New merge request', :target_branch => 'master') - }.to raise_error Gitlab::Error::MissingAttributes - end - - it "should fail if it doesn't have a target_branch" do - expect { - Gitlab.create_merge_request(3, 'New merge request', :source_branch => 'dev') - }.to raise_error Gitlab::Error::MissingAttributes - end - - it "should return information about a merge request" do - @merge_request = Gitlab.create_merge_request(3, 'New feature', - :source_branch => 'api', - :target_branch => 'master' - ) - expect(@merge_request.project_id).to eq(3) - expect(@merge_request.assignee.name).to eq("Jack Smith") - expect(@merge_request.title).to eq('New feature') - end - end - - describe ".update_merge_request" do - before do - stub_put("/projects/3/merge_request/2", "update_merge_request") - @merge_request = Gitlab.update_merge_request(3, 2, - :assignee_id => '1', - :target_branch => 'master', - :title => 'A different new feature' - ) - end - - it "should return information about a merge request" do - expect(@merge_request.project_id).to eq(3) - expect(@merge_request.assignee.name).to eq("Jack Smith") - expect(@merge_request.title).to eq('A different new feature') - end - end - - describe ".merge_request_comments" do - before do - stub_get("/projects/3/merge_request/2/comments", "merge_request_comments") - @merge_request = Gitlab.merge_request_comments(3, 2) - end - - it "should return merge request's comments" do - expect(@merge_request).to be_an Array - expect(@merge_request.length).to eq(2) - expect(@merge_request[0].note).to eq("this is the 1st comment on the 2merge merge request") - expect(@merge_request[0].author.id).to eq(11) - expect(@merge_request[1].note).to eq("another discussion point on the 2merge request") - expect(@merge_request[1].author.id).to eq(12) - end - end - - describe ".merge_request_comments" do - before do - stub_get("/projects/3/merge_request/2/comments", "merge_request_comments") - @merge_request = Gitlab.merge_request_comments(3, 2) - end - - it "should return merge request's comments" do - expect(@merge_request).to be_an Array - expect(@merge_request.length).to eq(2) - expect(@merge_request[0].note).to eq("this is the 1st comment on the 2merge merge request") - expect(@merge_request[0].author.id).to eq(11) - expect(@merge_request[1].note).to eq("another discussion point on the 2merge request") - expect(@merge_request[1].author.id).to eq(12) - end - end - - describe ".create_merge_request_comment" do - before do - stub_post("/projects/3/merge_request/2/comments", "comment_merge_request") - end - - it "should return information about a merge request" do - @merge_request = Gitlab.create_merge_request_comment(3, 2, 'Cool Merge Request!') - expect(@merge_request.note).to eq('Cool Merge Request!') - @merge_request.author.id == 1 - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/client/milestones_spec.rb b/lib/gitlab-cli/spec/gitlab/client/milestones_spec.rb deleted file mode 100644 index 5ec7f3e3..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/milestones_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - describe ".milestones" do - before do - stub_get("/projects/3/milestones", "milestones") - @milestones = Gitlab.milestones(3) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/milestones")).to have_been_made - end - - it "should return an array of project's milestones" do - expect(@milestones).to be_an Array - expect(@milestones.first.project_id).to eq(3) - end - end - - describe ".milestone" do - before do - stub_get("/projects/3/milestones/1", "milestone") - @milestone = Gitlab.milestone(3, 1) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/milestones/1")).to have_been_made - end - - it "should return information about a milestone" do - expect(@milestone.project_id).to eq(3) - end - end - - describe ".create_milestone" do - before do - stub_post("/projects/3/milestones", "milestone") - @milestone = Gitlab.create_milestone(3, 'title') - end - - it "should get the correct resource" do - expect(a_post("/projects/3/milestones"). - with(:body => {:title => 'title'})).to have_been_made - end - - it "should return information about a created milestone" do - expect(@milestone.project_id).to eq(3) - end - end - - describe ".edit_milestone" do - before do - stub_put("/projects/3/milestones/33", "milestone") - @milestone = Gitlab.edit_milestone(3, 33, :title => 'title') - end - - it "should get the correct resource" do - expect(a_put("/projects/3/milestones/33"). - with(:body => {:title => 'title'})).to have_been_made - end - - it "should return information about an edited milestone" do - expect(@milestone.project_id).to eq(3) - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/client/notes_spec.rb b/lib/gitlab-cli/spec/gitlab/client/notes_spec.rb deleted file mode 100644 index 78cd520d..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/notes_spec.rb +++ /dev/null @@ -1,156 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - describe "notes" do - context "when wall notes" do - before do - stub_get("/projects/3/notes", "notes") - @notes = Gitlab.notes(3) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/notes")).to have_been_made - end - - it "should return an array of notes" do - expect(@notes).to be_an Array - expect(@notes.first.author.name).to eq("John Smith") - end - end - - context "when issue notes" do - before do - stub_get("/projects/3/issues/7/notes", "notes") - @notes = Gitlab.issue_notes(3, 7) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/issues/7/notes")).to have_been_made - end - - it "should return an array of notes" do - expect(@notes).to be_an Array - expect(@notes.first.author.name).to eq("John Smith") - end - end - - context "when snippet notes" do - before do - stub_get("/projects/3/snippets/7/notes", "notes") - @notes = Gitlab.snippet_notes(3, 7) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/snippets/7/notes")).to have_been_made - end - - it "should return an array of notes" do - expect(@notes).to be_an Array - expect(@notes.first.author.name).to eq("John Smith") - end - end - end - - describe "note" do - context "when wall note" do - before do - stub_get("/projects/3/notes/1201", "note") - @note = Gitlab.note(3, 1201) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/notes/1201")).to have_been_made - end - - it "should return information about a note" do - expect(@note.body).to eq("The solution is rather tricky") - expect(@note.author.name).to eq("John Smith") - end - end - - context "when issue note" do - before do - stub_get("/projects/3/issues/7/notes/1201", "note") - @note = Gitlab.issue_note(3, 7, 1201) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/issues/7/notes/1201")).to have_been_made - end - - it "should return information about a note" do - expect(@note.body).to eq("The solution is rather tricky") - expect(@note.author.name).to eq("John Smith") - end - end - - context "when snippet note" do - before do - stub_get("/projects/3/snippets/7/notes/1201", "note") - @note = Gitlab.snippet_note(3, 7, 1201) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/snippets/7/notes/1201")).to have_been_made - end - - it "should return information about a note" do - expect(@note.body).to eq("The solution is rather tricky") - expect(@note.author.name).to eq("John Smith") - end - end - end - - describe "create note" do - context "when wall note" do - before do - stub_post("/projects/3/notes", "note") - @note = Gitlab.create_note(3, "The solution is rather tricky") - end - - it "should get the correct resource" do - expect(a_post("/projects/3/notes"). - with(:body => {:body => 'The solution is rather tricky'})).to have_been_made - end - - it "should return information about a created note" do - expect(@note.body).to eq("The solution is rather tricky") - expect(@note.author.name).to eq("John Smith") - end - end - - context "when issue note" do - before do - stub_post("/projects/3/issues/7/notes", "note") - @note = Gitlab.create_issue_note(3, 7, "The solution is rather tricky") - end - - it "should get the correct resource" do - expect(a_post("/projects/3/issues/7/notes"). - with(:body => {:body => 'The solution is rather tricky'})).to have_been_made - end - - it "should return information about a created note" do - expect(@note.body).to eq("The solution is rather tricky") - expect(@note.author.name).to eq("John Smith") - end - end - - context "when snippet note" do - before do - stub_post("/projects/3/snippets/7/notes", "note") - @note = Gitlab.create_snippet_note(3, 7, "The solution is rather tricky") - end - - it "should get the correct resource" do - expect(a_post("/projects/3/snippets/7/notes"). - with(:body => {:body => 'The solution is rather tricky'})).to have_been_made - end - - it "should return information about a created note" do - expect(@note.body).to eq("The solution is rather tricky") - expect(@note.author.name).to eq("John Smith") - end - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/client/projects_spec.rb b/lib/gitlab-cli/spec/gitlab/client/projects_spec.rb deleted file mode 100644 index 754a27c9..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/projects_spec.rb +++ /dev/null @@ -1,357 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - describe ".projects" do - before do - stub_get("/projects", "projects") - @projects = Gitlab.projects - end - - it "should get the correct resource" do - expect(a_get("/projects")).to have_been_made - end - - it "should return an array of projects" do - expect(@projects).to be_an Array - expect(@projects.first.name).to eq("Brute") - expect(@projects.first.owner.name).to eq("John Smith") - end - end - - describe ".project" do - before do - stub_get("/projects/3", "project") - @project = Gitlab.project(3) - end - - it "should get the correct resource" do - expect(a_get("/projects/3")).to have_been_made - end - - it "should return information about a project" do - expect(@project.name).to eq("Gitlab") - expect(@project.owner.name).to eq("John Smith") - end - end - - describe ".project_events" do - before do - stub_get("/projects/2/events", "project_events") - @events = Gitlab.project_events(2) - end - - it "should get the correct resource" do - expect(a_get("/projects/2/events")).to have_been_made - end - - it "should return an array of events" do - expect(@events).to be_an Array - expect(@events.size).to eq(2) - end - - it "should return the action name of the event" do - expect(@events.first.action_name).to eq("opened") - end - end - - describe ".create_project" do - before do - stub_post("/projects", "project") - @project = Gitlab.create_project('Gitlab') - end - - it "should get the correct resource" do - expect(a_post("/projects")).to have_been_made - end - - it "should return information about a created project" do - expect(@project.name).to eq("Gitlab") - expect(@project.owner.name).to eq("John Smith") - end - end - - describe ".create_project for user" do - before do - stub_post("/users", "user") - @owner = Gitlab.create_user("john@example.com", "pass", {name: 'John Owner'}) - stub_post("/projects/user/#{@owner.id}", "project_for_user") - @project = Gitlab.create_project('Brute', {:user_id => @owner.id}) - end - - it "should return information about a created project" do - expect(@project.name).to eq("Brute") - expect(@project.owner.name).to eq("John Owner") - end - end - - describe ".delete_project" do - before do - stub_delete("/projects/Gitlab", "project") - @project = Gitlab.delete_project('Gitlab') - end - - it "should get the correct resource" do - expect(a_delete("/projects/Gitlab")).to have_been_made - end - - it "should return information about a deleted project" do - expect(@project.name).to eq("Gitlab") - expect(@project.owner.name).to eq("John Smith") - end - end - - describe ".team_members" do - before do - stub_get("/projects/3/members", "team_members") - @team_members = Gitlab.team_members(3) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/members")).to have_been_made - end - - it "should return an array of team members" do - expect(@team_members).to be_an Array - expect(@team_members.first.name).to eq("John Smith") - end - end - - describe ".team_member" do - before do - stub_get("/projects/3/members/1", "team_member") - @team_member = Gitlab.team_member(3, 1) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/members/1")).to have_been_made - end - - it "should return information about a team member" do - expect(@team_member.name).to eq("John Smith") - end - end - - describe ".add_team_member" do - before do - stub_post("/projects/3/members", "team_member") - @team_member = Gitlab.add_team_member(3, 1, 40) - end - - it "should get the correct resource" do - expect(a_post("/projects/3/members"). - with(:body => {:user_id => '1', :access_level => '40'})).to have_been_made - end - - it "should return information about an added team member" do - expect(@team_member.name).to eq("John Smith") - end - end - - describe ".edit_team_member" do - before do - stub_put("/projects/3/members/1", "team_member") - @team_member = Gitlab.edit_team_member(3, 1, 40) - end - - it "should get the correct resource" do - expect(a_put("/projects/3/members/1"). - with(:body => {:access_level => '40'})).to have_been_made - end - - it "should return information about an edited team member" do - expect(@team_member.name).to eq("John Smith") - end - end - - describe ".remove_team_member" do - before do - stub_delete("/projects/3/members/1", "team_member") - @team_member = Gitlab.remove_team_member(3, 1) - end - - it "should get the correct resource" do - expect(a_delete("/projects/3/members/1")).to have_been_made - end - - it "should return information about a removed team member" do - expect(@team_member.name).to eq("John Smith") - end - end - - describe ".project_hooks" do - before do - stub_get("/projects/1/hooks", "project_hooks") - @hooks = Gitlab.project_hooks(1) - end - - it "should get the correct resource" do - expect(a_get("/projects/1/hooks")).to have_been_made - end - - it "should return an array of hooks" do - expect(@hooks).to be_an Array - expect(@hooks.first.url).to eq("https://api.example.net/v1/webhooks/ci") - end - end - - describe ".project_hook" do - before do - stub_get("/projects/1/hooks/1", "project_hook") - @hook = Gitlab.project_hook(1, 1) - end - - it "should get the correct resource" do - expect(a_get("/projects/1/hooks/1")).to have_been_made - end - - it "should return information about a hook" do - expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") - end - end - - describe ".add_project_hook" do - context "without specified events" do - before do - stub_post("/projects/1/hooks", "project_hook") - @hook = Gitlab.add_project_hook(1, "https://api.example.net/v1/webhooks/ci") - end - - it "should get the correct resource" do - body = {:url => "https://api.example.net/v1/webhooks/ci"} - expect(a_post("/projects/1/hooks").with(:body => body)).to have_been_made - end - - it "should return information about an added hook" do - expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") - end - end - - context "with specified events" do - before do - stub_post("/projects/1/hooks", "project_hook") - @hook = Gitlab.add_project_hook(1, "https://api.example.net/v1/webhooks/ci", push_events: true, merge_requests_events: true) - end - - it "should get the correct resource" do - body = {:url => "https://api.example.net/v1/webhooks/ci", push_events: "true", merge_requests_events: "true"} - expect(a_post("/projects/1/hooks").with(:body => body)).to have_been_made - end - - it "should return information about an added hook" do - expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") - end - end - end - - describe ".edit_project_hook" do - before do - stub_put("/projects/1/hooks/1", "project_hook") - @hook = Gitlab.edit_project_hook(1, 1, "https://api.example.net/v1/webhooks/ci") - end - - it "should get the correct resource" do - body = {:url => "https://api.example.net/v1/webhooks/ci"} - expect(a_put("/projects/1/hooks/1").with(:body => body)).to have_been_made - end - - it "should return information about an edited hook" do - expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") - end - end - - describe ".delete_project_hook" do - before do - stub_delete("/projects/1/hooks/1", "project_hook") - @hook = Gitlab.delete_project_hook(1, 1) - end - - it "should get the correct resource" do - expect(a_delete("/projects/1/hooks/1")).to have_been_made - end - - it "should return information about a deleted hook" do - expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") - end - end - - describe ".make_forked_from" do - before do - stub_post("/projects/42/fork/24", "project_fork_link") - @forked_project_link = Gitlab.make_forked_from(42, 24) - end - - it "should get the correct resource" do - expect(a_post("/projects/42/fork/24")).to have_been_made - end - - it "should return information about a forked project" do - expect(@forked_project_link.forked_from_project_id).to eq(24) - expect(@forked_project_link.forked_to_project_id).to eq(42) - end - end - - describe ".remove_forked" do - before do - stub_delete("/projects/42/fork", "project_fork_link") - @forked_project_link = Gitlab.remove_forked(42) - end - - it "should be sent to correct resource" do - expect(a_delete("/projects/42/fork")).to have_been_made - end - - it "should return information about an unforked project" do - expect(@forked_project_link.forked_to_project_id).to eq(42) - end - end - - describe ".deploy_keys" do - before do - stub_get("/projects/42/keys", "project_keys") - @deploy_keys = Gitlab.deploy_keys(42) - end - - it "should get the correct resource" do - expect(a_get("/projects/42/keys")).to have_been_made - end - - it "should return project deploy keys" do - expect(@deploy_keys).to be_an Array - expect(@deploy_keys.first.id).to eq 2 - expect(@deploy_keys.first.title).to eq "Key Title" - expect(@deploy_keys.first.key).to match(/ssh-rsa/) - end - end - - describe ".deploy_key" do - before do - stub_get("/projects/42/keys/2", "project_key") - @deploy_key = Gitlab.deploy_key(42, 2) - end - - it "should get the correct resource" do - expect(a_get("/projects/42/keys/2")).to have_been_made - end - - it "should return project deploy key" do - expect(@deploy_key.id).to eq 2 - expect(@deploy_key.title).to eq "Key Title" - expect(@deploy_key.key).to match(/ssh-rsa/) - end - end - - describe ".delete_deploy_key" do - before do - stub_delete("/projects/42/keys/2", "project_delete_key") - @deploy_key = Gitlab.delete_deploy_key(42, 2) - end - - it "should get the correct resource" do - expect(a_delete("/projects/42/keys/2")).to have_been_made - end - - it "should return information about a deleted key" do - expect(@deploy_key.id).to eq(2) - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/client/repositories_spec.rb b/lib/gitlab-cli/spec/gitlab/client/repositories_spec.rb deleted file mode 100644 index 0bcc8de5..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/repositories_spec.rb +++ /dev/null @@ -1,92 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - it { should respond_to :repo_tags } - it { should respond_to :repo_create_tag } - it { should respond_to :repo_branches } - it { should respond_to :repo_branch } - it { should respond_to :repo_commits } - it { should respond_to :repo_commit } - it { should respond_to :repo_commit_diff } - - describe ".tags" do - before do - stub_get("/projects/3/repository/tags", "project_tags") - @tags = Gitlab.tags(3) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/repository/tags")).to have_been_made - end - - it "should return an array of repository tags" do - expect(@tags).to be_an Array - expect(@tags.first.name).to eq("v2.8.2") - end - end - - describe ".create_tag" do - before do - stub_post("/projects/3/repository/tags", "tag") - @tag = Gitlab.create_tag(3, 'v1.0.0', '2695effb5807a22ff3d138d593fd856244e155e7') - end - - it "should get the correct resource" do - expect(a_post("/projects/3/repository/tags")).to have_been_made - end - - it "should return information about a new repository tag" do - expect(@tag.name).to eq("v1.0.0") - end - end - - describe ".commits" do - before do - stub_get("/projects/3/repository/commits", "project_commits"). - with(:query => {:ref_name => "api"}) - @commits = Gitlab.commits(3, :ref_name => "api") - end - - it "should get the correct resource" do - expect(a_get("/projects/3/repository/commits"). - with(:query => {:ref_name => "api"})).to have_been_made - end - - it "should return an array of repository commits" do - expect(@commits).to be_an Array - expect(@commits.first.id).to eq("f7dd067490fe57505f7226c3b54d3127d2f7fd46") - end - end - - describe ".commit" do - before do - stub_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6", "project_commit") - @commit = Gitlab.commit(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6') - end - - it "should get the correct resource" do - expect(a_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6")) - .to have_been_made - end - - it "should return a repository commit" do - expect(@commit.id).to eq("6104942438c14ec7bd21c6cd5bd995272b3faff6") - end - end - - describe ".commit_diff" do - before do - stub_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/diff", "project_commit_diff") - @diff = Gitlab.commit_diff(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6') - end - - it "should get the correct resource" do - expect(a_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/diff")) - .to have_been_made - end - - it "should return a diff of a commit" do - expect(@diff.new_path).to eq("doc/update/5.4-to-6.0.md") - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/client/snippets_spec.rb b/lib/gitlab-cli/spec/gitlab/client/snippets_spec.rb deleted file mode 100644 index 751c4d0b..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/snippets_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - describe ".snippets" do - before do - stub_get("/projects/3/snippets", "snippets") - @snippets = Gitlab.snippets(3) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/snippets")).to have_been_made - end - - it "should return an array of project's snippets" do - expect(@snippets).to be_an Array - expect(@snippets.first.file_name).to eq("mailer_test.rb") - end - end - - describe ".snippet" do - before do - stub_get("/projects/3/snippets/1", "snippet") - @snippet = Gitlab.snippet(3, 1) - end - - it "should get the correct resource" do - expect(a_get("/projects/3/snippets/1")).to have_been_made - end - - it "should return information about a snippet" do - expect(@snippet.file_name).to eq("mailer_test.rb") - expect(@snippet.author.name).to eq("John Smith") - end - end - - describe ".create_snippet" do - before do - stub_post("/projects/3/snippets", "snippet") - @snippet = Gitlab.create_snippet(3, {:title => 'API', :file_name => 'api.rb', :code => 'code'}) - end - - it "should get the correct resource" do - body = {:title => 'API', :file_name => 'api.rb', :code => 'code'} - expect(a_post("/projects/3/snippets").with(:body => body)).to have_been_made - end - - it "should return information about a new snippet" do - expect(@snippet.file_name).to eq("mailer_test.rb") - expect(@snippet.author.name).to eq("John Smith") - end - end - - describe ".edit_snippet" do - before do - stub_put("/projects/3/snippets/1", "snippet") - @snippet = Gitlab.edit_snippet(3, 1, :file_name => 'mailer_test.rb') - end - - it "should get the correct resource" do - expect(a_put("/projects/3/snippets/1"). - with(:body => {:file_name => 'mailer_test.rb'})).to have_been_made - end - - it "should return information about an edited snippet" do - expect(@snippet.file_name).to eq("mailer_test.rb") - expect(@snippet.author.name).to eq("John Smith") - end - end - - describe ".delete_snippet" do - before do - stub_delete("/projects/3/snippets/1", "snippet") - @snippet = Gitlab.delete_snippet(3, 1) - end - - it "should get the correct resource" do - expect(a_delete("/projects/3/snippets/1")).to have_been_made - end - - it "should return information about a deleted snippet" do - expect(@snippet.file_name).to eq("mailer_test.rb") - expect(@snippet.author.name).to eq("John Smith") - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/client/system_hooks_spec.rb b/lib/gitlab-cli/spec/gitlab/client/system_hooks_spec.rb deleted file mode 100644 index 754e8684..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/system_hooks_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - it { should respond_to :system_hooks } - it { should respond_to :add_system_hook } - it { should respond_to :system_hook } - it { should respond_to :delete_system_hook } - - describe ".hooks" do - before do - stub_get("/hooks", "system_hooks") - @hooks = Gitlab.hooks - end - - it "should get the correct resource" do - expect(a_get("/hooks")).to have_been_made - end - - it "should return an array of system hooks" do - expect(@hooks).to be_an Array - expect(@hooks.first.url).to eq("http://example.com/hook") - end - end - - describe ".add_hook" do - before do - stub_post("/hooks", "system_hook") - @hook = Gitlab.add_hook("http://example.com/hook") - end - - it "should get the correct resource" do - expect(a_post("/hooks")).to have_been_made - end - - it "should return information about a added system hook" do - expect(@hook.url).to eq("http://example.com/hook") - end - end - - describe ".hook" do - before do - stub_get("/hooks/3", "system_hook_test") - @hook = Gitlab.hook(3) - end - it "should get the correct resource" do - expect(a_get("/hooks/3")).to have_been_made - end - - it "should return information about a added system hook" do - expect(@hook.event_name).to eq("project_create") - expect(@hook.project_id).to eq(1) - end - end - - describe ".delete_hook" do - before do - stub_delete("/hooks/3", "system_hook") - @hook = Gitlab.delete_hook(3) - end - - it "should get the correct resource" do - expect(a_delete("/hooks/3")).to have_been_made - end - - it "should return information about a deleted system hook" do - expect(@hook.url).to eq("http://example.com/hook") - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/client/users_spec.rb b/lib/gitlab-cli/spec/gitlab/client/users_spec.rb deleted file mode 100644 index cfbc7d50..00000000 --- a/lib/gitlab-cli/spec/gitlab/client/users_spec.rb +++ /dev/null @@ -1,192 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Client do - describe ".users" do - before do - stub_get("/users", "users") - @users = Gitlab.users - end - - it "should get the correct resource" do - expect(a_get("/users")).to have_been_made - end - - it "should return an array of users" do - expect(@users).to be_an Array - expect(@users.first.email).to eq("john@example.com") - end - end - - describe ".user" do - context "with user ID passed" do - before do - stub_get("/users/1", "user") - @user = Gitlab.user(1) - end - - it "should get the correct resource" do - expect(a_get("/users/1")).to have_been_made - end - - it "should return information about a user" do - expect(@user.email).to eq("john@example.com") - end - end - - context "without user ID passed" do - before do - stub_get("/user", "user") - @user = Gitlab.user - end - - it "should get the correct resource" do - expect(a_get("/user")).to have_been_made - end - - it "should return information about an authorized user" do - expect(@user.email).to eq("john@example.com") - end - end - end - - describe ".create_user" do - context "when successful request" do - before do - stub_post("/users", "user") - @user = Gitlab.create_user("email", "pass") - end - - it "should get the correct resource" do - body = {:email => "email", :password => "pass", :name => "email"} - expect(a_post("/users").with(:body => body)).to have_been_made - end - - it "should return information about a created user" do - expect(@user.email).to eq("john@example.com") - end - end - - context "when bad request" do - it "should throw an exception" do - stub_post("/users", "error_already_exists", 409) - expect { - Gitlab.create_user("email", "pass") - }.to raise_error(Gitlab::Error::Conflict, "Server responded with code 409, message: 409 Already exists. Request URI: #{Gitlab.endpoint}/users") - end - end - end - - describe ".edit_user" do - before do - @options = { :name => "Roberto" } - stub_put("/users/1", "user").with(:body => @options) - @user = Gitlab.edit_user(1, @options) - end - - it "should get the correct resource" do - expect(a_put("/users/1").with(:body => @options)).to have_been_made - end - end - - describe ".session" do - after do - Gitlab.endpoint = 'https://api.example.com' - Gitlab.private_token = 'secret' - end - - before do - stub_request(:post, "#{Gitlab.endpoint}/session"). - to_return(:body => load_fixture('session'), :status => 200) - @session = Gitlab.session("email", "pass") - end - - context "when endpoint is not set" do - it "should raise Error::MissingCredentials" do - Gitlab.endpoint = nil - expect { - Gitlab.session("email", "pass") - }.to raise_error(Gitlab::Error::MissingCredentials, 'Please set an endpoint to API') - end - end - - context "when private_token is not set" do - it "should not raise Error::MissingCredentials" do - Gitlab.private_token = nil - expect { Gitlab.session("email", "pass") }.to_not raise_error - end - end - - context "when endpoint is set" do - it "should get the correct resource" do - expect(a_request(:post, "#{Gitlab.endpoint}/session")).to have_been_made - end - - it "should return information about a created session" do - expect(@session.email).to eq("john@example.com") - expect(@session.private_token).to eq("qEsq1pt6HJPaNciie3MG") - end - end - end - - describe ".ssh_keys" do - before do - stub_get("/user/keys", "keys") - @keys = Gitlab.ssh_keys - end - - it "should get the correct resource" do - expect(a_get("/user/keys")).to have_been_made - end - - it "should return an array of SSH keys" do - expect(@keys).to be_an Array - expect(@keys.first.title).to eq("narkoz@helium") - end - end - - describe ".ssh_key" do - before do - stub_get("/user/keys/1", "key") - @key = Gitlab.ssh_key(1) - end - - it "should get the correct resource" do - expect(a_get("/user/keys/1")).to have_been_made - end - - it "should return information about an SSH key" do - expect(@key.title).to eq("narkoz@helium") - end - end - - describe ".create_ssh_key" do - before do - stub_post("/user/keys", "key") - @key = Gitlab.create_ssh_key("title", "body") - end - - it "should get the correct resource" do - body = {:title => "title", :key => "body"} - expect(a_post("/user/keys").with(:body => body)).to have_been_made - end - - it "should return information about a created SSH key" do - expect(@key.title).to eq("narkoz@helium") - end - end - - describe ".delete_ssh_key" do - before do - stub_delete("/user/keys/1", "key") - @key = Gitlab.delete_ssh_key(1) - end - - it "should get the correct resource" do - expect(a_delete("/user/keys/1")).to have_been_made - end - - it "should return information about a deleted SSH key" do - expect(@key.title).to eq("narkoz@helium") - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/objectified_hash_spec.rb b/lib/gitlab-cli/spec/gitlab/objectified_hash_spec.rb deleted file mode 100644 index 5a166dc7..00000000 --- a/lib/gitlab-cli/spec/gitlab/objectified_hash_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'spec_helper' - -describe Gitlab::ObjectifiedHash do - before do - @hash = {a: 1, b: 2} - @oh = Gitlab::ObjectifiedHash.new @hash - end - - it "should objectify hash" do - expect(@oh.a).to eq(@hash[:a]) - expect(@oh.b).to eq(@hash[:b]) - end - - describe "#to_hash" do - it "should return an original hash" do - expect(@oh.to_hash).to eq(@hash) - end - - it "should have an alias #to_h" do - expect(@oh.respond_to?(:to_h)).to be_truthy - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab/request_spec.rb b/lib/gitlab-cli/spec/gitlab/request_spec.rb deleted file mode 100644 index 29125d08..00000000 --- a/lib/gitlab-cli/spec/gitlab/request_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Request do - it { should respond_to :get } - it { should respond_to :post } - it { should respond_to :put } - it { should respond_to :delete } - - describe ".default_options" do - it "should have default values" do - default_options = Gitlab::Request.default_options - expect(default_options).to be_a Hash - expect(default_options[:parser]).to be_a Proc - expect(default_options[:format]).to eq(:json) - expect(default_options[:headers]).to eq({'Accept' => 'application/json'}) - expect(default_options[:default_params]).to be_nil - end - end - - describe ".parse" do - it "should return ObjectifiedHash" do - body = JSON.unparse({a: 1, b: 2}) - expect(Gitlab::Request.parse(body)).to be_an Gitlab::ObjectifiedHash - end - end - - describe "#set_request_defaults" do - context "when endpoint is not set" do - it "should raise Error::MissingCredentials" do - expect { - Gitlab::Request.new.set_request_defaults(nil, 1234000) - }.to raise_error(Gitlab::Error::MissingCredentials, 'Please set an endpoint to API') - end - end - - context "when endpoint is set" do - it "should set base_uri" do - Gitlab::Request.new.set_request_defaults('http://rabbit-hole.example.org', 1234000) - expect(Gitlab::Request.base_uri).to eq("http://rabbit-hole.example.org") - end - - it "should set default_params" do - Gitlab::Request.new.set_request_defaults('http://rabbit-hole.example.org', 1234000, 'sudoer') - expect(Gitlab::Request.default_params).to eq({:sudo => 'sudoer'}) - end - end - end -end diff --git a/lib/gitlab-cli/spec/gitlab_spec.rb b/lib/gitlab-cli/spec/gitlab_spec.rb deleted file mode 100644 index 7a1ada4d..00000000 --- a/lib/gitlab-cli/spec/gitlab_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'spec_helper' - -describe Gitlab do - after { Gitlab.reset } - - describe ".client" do - it "should be a Gitlab::Client" do - expect(Gitlab.client).to be_a Gitlab::Client - end - end - - describe ".actions" do - it "should return an array of client methods" do - actions = Gitlab.actions - expect(actions).to be_an Array - expect(actions.first).to be_a Symbol - expect(actions.sort.first).to match(/add_/) - end - end - - describe ".endpoint=" do - it "should set endpoint" do - Gitlab.endpoint = 'https://api.example.com' - expect(Gitlab.endpoint).to eq('https://api.example.com') - end - end - - describe ".private_token=" do - it "should set private_token" do - Gitlab.private_token = 'secret' - expect(Gitlab.private_token).to eq('secret') - end - end - - describe ".sudo=" do - it "should set sudo" do - Gitlab.sudo = 'user' - expect(Gitlab.sudo).to eq('user') - end - end - - describe ".user_agent" do - it "should return default user_agent" do - expect(Gitlab.user_agent).to eq(Gitlab::Configuration::DEFAULT_USER_AGENT) - end - end - - describe ".user_agent=" do - it "should set user_agent" do - Gitlab.user_agent = 'Custom User Agent' - expect(Gitlab.user_agent).to eq('Custom User Agent') - end - end - - describe ".configure" do - Gitlab::Configuration::VALID_OPTIONS_KEYS.each do |key| - it "should set #{key}" do - Gitlab.configure do |config| - config.send("#{key}=", key) - expect(Gitlab.send(key)).to eq(key) - end - end - end - end -end diff --git a/lib/gitlab-cli/spec/spec_helper.rb b/lib/gitlab-cli/spec/spec_helper.rb deleted file mode 100644 index 06d57c84..00000000 --- a/lib/gitlab-cli/spec/spec_helper.rb +++ /dev/null @@ -1,74 +0,0 @@ -require 'rspec' -require 'webmock/rspec' - -require File.expand_path('../../lib/gitlab', __FILE__) -require File.expand_path('../../lib/gitlab/cli', __FILE__) - -def capture_output - out = StringIO.new - $stdout = out - $stderr = out - yield - $stdout = STDOUT - $stderr = STDERR - out.string -end - -def load_fixture(name) - File.new(File.dirname(__FILE__) + "/fixtures/#{name}.json") -end - -RSpec.configure do |config| - config.before(:all) do - Gitlab.endpoint = 'https://api.example.com' - Gitlab.private_token = 'secret' - end -end - -# GET -def stub_get(path, fixture) - stub_request(:get, "#{Gitlab.endpoint}#{path}"). - with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). - to_return(:body => load_fixture(fixture)) -end - -def a_get(path) - a_request(:get, "#{Gitlab.endpoint}#{path}"). - with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) -end - -# POST -def stub_post(path, fixture, status_code=200) - stub_request(:post, "#{Gitlab.endpoint}#{path}"). - with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). - to_return(:body => load_fixture(fixture), :status => status_code) -end - -def a_post(path) - a_request(:post, "#{Gitlab.endpoint}#{path}"). - with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) -end - -# PUT -def stub_put(path, fixture) - stub_request(:put, "#{Gitlab.endpoint}#{path}"). - with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). - to_return(:body => load_fixture(fixture)) -end - -def a_put(path) - a_request(:put, "#{Gitlab.endpoint}#{path}"). - with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) -end - -# DELETE -def stub_delete(path, fixture) - stub_request(:delete, "#{Gitlab.endpoint}#{path}"). - with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). - to_return(:body => load_fixture(fixture)) -end - -def a_delete(path) - a_request(:delete, "#{Gitlab.endpoint}#{path}"). - with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) -end diff --git a/lib/tasks/auto_annotate_models.rake b/lib/tasks/auto_annotate_models.rake new file mode 100644 index 00000000..356d43fc --- /dev/null +++ b/lib/tasks/auto_annotate_models.rake @@ -0,0 +1,34 @@ +# NOTE: only doing this in development as some production environments (Heroku) +# NOTE: are sensitive to local FS writes, and besides -- it's just not proper +# NOTE: to have a dev-mode tool do its thing in production. +if Rails.env.development? + task :set_annotation_options do + # You can override any of these by setting an environment variable of the + # same name. + Annotate.set_defaults({ + 'position_in_routes' => "before", + 'position_in_class' => "before", + 'position_in_test' => "before", + 'position_in_fixture' => "before", + 'position_in_factory' => "before", + 'show_indexes' => "true", + 'simple_indexes' => "false", + 'model_dir' => "app/models", + 'include_version' => "false", + 'require' => "", + 'exclude_tests' => "true", + 'exclude_fixtures' => "true", + 'exclude_factories' => "false", + 'ignore_model_sub_dir' => "false", + 'skip_on_db_migrate' => "false", + 'format_bare' => "true", + 'format_rdoc' => "false", + 'format_markdown' => "false", + 'sort' => "false", + 'force' => "false", + 'trace' => "false", + }) + end + + Annotate.load_tasks +end diff --git a/lib/tasks/dev_ops_languages.rake b/lib/tasks/dev_ops_languages.rake new file mode 100644 index 00000000..348fb932 --- /dev/null +++ b/lib/tasks/dev_ops_languages.rake @@ -0,0 +1,752 @@ +desc "Initialize the data for dev ops languages" +namespace :dev_ops_languages do + + task init: :environment do + # DevOps::Language.bulk_insert do |worker| + # languages.each do |attrs| + # worker.add(attrs) + # end + # end + + languages.each do |l| + content = Base64.encode64 l[:content] + Ci::Language.create!(name: l[:name], content: content) + end + end + + def languages + [ + { + name: "C", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: gcc + commands: + - ./configure + - make + - make test" + }, + { + name: "C++", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: gcc + commands: + - ./configure + - make + - make test" + }, + { + name: "Docker", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: docker:dind + volumes: + - name: dockersock + path: /var/run/docker.sock + commands: + - docker ps -a + +volumes: +- name: dockersock + host: + path: /var/run/docker.sock" + }, + { + name: "Java", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: maven:3-jdk-10 + commands: + - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V + - mvn test -B" + }, + { + name: "R", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: r-base + commands: + - R -e 'install.packages(c('package1','package2'))' + - R CMD build ." + }, + { + name: "Ruby", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: ruby + commands: + - bundle install --jobs=3 --retry=3 + - rake" + }, + { + name: "PHP", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: install + image: composer + commands: + - composer install + +- name: test + image: php:7 + commands: + - vendor/bin/phpunit --configuration config.xml" + }, + { + name: "Python", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: python + commands: + - pip install -r requirements.txt + - pytest" + }, + { + name: "MySQL", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: mysql + commands: + - sleep 15 + - mysql -u root -h database --execute='SELECT VERSION();' + +services: +- name: database + image: mysql + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' + MYSQL_DATABASE: test" + }, + { + name: "MongoDB", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: ping + image: mongo:4 + commands: + - sleep 5 + - mongo --host mongo --eval 'db.version()' + +services: +- name: mongo + image: mongo:4 + command: [ --smallfiles ]" + }, + { + name: "Clojure", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: clojure + commands: + - lein test" + }, + { + name: "CouchDB", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: couchdb:2.2 + commands: + - sleep 15 + - curl http://database:5984 + +services: +- name: database + image: couchdb:2.2" + }, + { + name: "Crystal", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: crystallang/crystal + commands: + - shards install + - crystal spec.2" + }, + { + name: "D", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: dlanguage/dmd + commands: + - dub test" + }, + { + name: "Dart", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: google/dart + commands: + - pub get + - pub run test" + }, + { + name: "Docker (dind)", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: docker:dind + volumes: + - name: dockersock + path: /var/run + commands: + - sleep 5 # give docker enough time to start + - docker ps -a + +services: +- name: docker + image: docker:dind + privileged: true + volumes: + - name: dockersock + path: /var/run + +volumes: +- name: dockersock + temp: {}" + }, + { + name: "Elasticsearch", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: alpine:3.8 + commands: + - apk add curl + - sleep 45 + - curl http://database:9200 + +services: +- name: database + image: elasticsearch:5-alpine" + }, + { + name: "Elixir", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: elixir:1.5 + commands: + - mix local.rebar --force + - mix local.hex --force + - mix deps.get + - mix test" + }, + { + name: "Erlang", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: erlang:21 + commands: + - rebar get-deps + - rebar compile + - rebar skip_deps=true eunit" + }, + { + name: "20.Go (with Gopath)", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +workspace: + base: /go + path: src/hello-world + +steps: +- name: test + image: golang + commands: + - go get + - go test" + }, + { + name: "21.Go (with Modules)", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: golang + commands: + - go test + - go build" + }, + { + name: "Gradle", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: gradle:jdk10 + commands: + - gradle assemble + - gradle check" + }, + { + name: "Groovy", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: gradle:2.5-jdk8 + commands: + - ./gradlew assemble + - ./gradlew check" + }, + { + name: "Haskell", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: haskell + commands: + - cabal install --only-dependencies --enable-tests + - cabal configure --enable-tests + - cabal build + - cabal test" + }, + { + name: "Haxe", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: haxe + commands: + - haxelib install build.hxml + - haxe build.hxml" + }, + { + name: "MariaDB", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: mariadb + commands: + - sleep 15 + - mysql -u root -h database --execute='SELECT VERSION();' + +services: +- name: database + image: mariadb + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' + MYSQL_DATABASE: test" + }, + { + name: "Maven", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: maven:3-jdk-10 + commands: + - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V + - mvn test -B" + }, + { + name: "Memcached", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: ubuntu + commands: + - apt-get update -qq + - apt-get install -y -qq telnet > /dev/null + - (sleep 1; echo 'stats'; sleep 2; echo 'quit';) | telnet cache 11211 || true + +services: +- name: cache + image: memcached:alpine + command: [ -vv ]" + }, + { + name: "Nats", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: ruby:2 + commands: + - gem install nats + - nats-pub -s tcp://nats:4222 greeting 'hello' + - nats-pub -s tcp://nats:4222 greeting 'world' + +services: +- name: nats + image: nats:1.3.0" + }, + { + name: "Node", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: node + commands: + - npm install + - npm test" + }, + { + name: "Perl", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: perl + commands: + - cpanm --quiet --installdeps --notest . + - perl Build.PL + - ./Build test" + }, + { + name: "Postgres", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: postgres:9-alpine + commands: + - psql -U postgres -d test -h database + +services: +- name: database + image: postgres:9-alpine + environment: + POSTGRES_USER: postgres + POSTGRES_DB: test" + }, + { + name: "Redis", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: redis + commands: + - sleep 5 + - redis-cli -h redis ping + - redis-cli -h redis set FOO bar + - redis-cli -h redis get FOO + +services: +- name: redis + image: redis" + }, + { + name: "RethinkDB", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: node:9 + commands: + - npm install -s -g recli + - recli -h database -j 'r.db('rethinkdb').table('stats')' + +services: +- name: database + image: rethinkdb:2 + command: [ rethinkdb, --bind, all ]" + }, + { + name: "Rust", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: rust:1.30 + commands: + - cargo build --verbose --all + - cargo test --verbose --all" + }, + { + name: "Swift", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: swift:4 + commands: + - swift build + - swift test" + }, + { + name: "Vault", + content: " +kind: pipeline +name: default + +platform: + os: linux + arch: arm64 + +steps: +- name: test + image: vault:1.0.0-beta2 + environment: + VAULT_ADDR: http://vault:8200 + VAULT_TOKEN: dummy + commands: + - sleep 5 + - vault kv put secret/my-secret my-value=s3cr3t + - vault kv get secret/my-secret + +services: +- name: vault + image: vault:1.0.0-beta2 + environment: + VAULT_DEV_ROOT_TOKEN_ID: dummy" + } + ] + end +end diff --git a/lib/tasks/sync_table_structure.rake b/lib/tasks/sync_table_structure.rake index e1a775c5..026d5214 100644 --- a/lib/tasks/sync_table_structure.rake +++ b/lib/tasks/sync_table_structure.rake @@ -4,7 +4,17 @@ namespace :sync_table_structure do task import_csv: :environment do puts "init table structure......." - system "mysql -uroot -poracle10g -h127.0.0.1 forge_development < #{Rails.root}/db/structure.sql" + database_config = Rails.configuration.database_configuration + + database = database_config[Rails.env]["database"] + database_username = database_config[Rails.env]["username"] + database_password = database_config[Rails.env]["password"] + database_host = database_config[Rails.env]["host"] + database_port = database_config[Rails.env]["port"] || 3306 + + puts "bash: mysql -u#{database_username} -p#{database_password} -P#{database_port} -h#{database_host} #{database}" + + system "mysql -u#{database_username} -p#{database_password} -P#{database_port} -h#{database_host} #{database} < #{Rails.root}/db/structure.sql" puts "init success" end diff --git a/public/images/oauth/backImg.png b/public/images/oauth/backImg.png new file mode 100644 index 00000000..450002fa Binary files /dev/null and b/public/images/oauth/backImg.png differ diff --git a/public/images/oauth/logo.png b/public/images/oauth/logo.png new file mode 100644 index 00000000..4d0b489b Binary files /dev/null and b/public/images/oauth/logo.png differ diff --git a/public/react/build b/public/react/build deleted file mode 160000 index 447edde1..00000000 --- a/public/react/build +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 447edde157092e65f05b36bc41c472659c482c6a diff --git a/public/stylesheets/css/oauth.css b/public/stylesheets/css/oauth.css new file mode 100644 index 00000000..e862b52d --- /dev/null +++ b/public/stylesheets/css/oauth.css @@ -0,0 +1,78 @@ +html{margin:0px;padding: 0px;font-size: 14px;font-family: "微软雅黑","宋体";} +body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { + margin: 0; + padding: 0; +} +.IndexContent{ + height: 100vh; + width: 100%; + position: relative; + background-image: url('/images/oauth/backImg.png'); + background-repeat: no-repeat; + background-size: cover; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; +} +.indexLogo{ + width:80px; + margin-bottom: 35px; +} +.indexPanel{ + width: 580px; + min-height: 400px; + background-color: #fff; + box-shadow: 0px 2px 10px 5px rgba(0,0,0,0.05); + border-radius: 5px; + box-sizing: border-box; +} +.indexTitle{ + height: 75px; + line-height: 75px; + font-size: 18px; + color:#333; + text-align: center; + border-bottom: 1px solid #eee; +} +.indexInfo{ + display: flex; + flex-direction: column; + align-items: flex-start; +} +.indexInfos{ + padding:40px 60px; +} +.indexInfo > span{ + color: #333; + font-size: 16px; + margin-top: 5px; +} +.indexInfo input{ + width: 100%; + height:40px; + border-radius: 2px; + border:1px solid #eee; + margin-top: 5px; + padding:0px 0px 0px 8px; + outline: none; +} +.indexInfo .checkInfo{ + height: 15px; + color: red; +} +.indexBtn{ + text-align: center; + margin-top: 20px; +} +.indexSubmit{ + width: 50%; + height: 32px; + line-height: 32px; + background-color: #1890FF; + border:none; + color: #fff; + border-radius: 2px; + cursor: pointer; + outline: none; +} diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb new file mode 100644 index 00000000..3246d09e --- /dev/null +++ b/spec/models/ci/build_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Ci::Build, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/ci/repo_spec.rb b/spec/models/ci/repo_spec.rb new file mode 100644 index 00000000..40753699 --- /dev/null +++ b/spec/models/ci/repo_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Ci::Repo, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb new file mode 100644 index 00000000..ba43cca2 --- /dev/null +++ b/spec/models/ci/stage_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Ci::Stage, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/ci/step_spec.rb b/spec/models/ci/step_spec.rb new file mode 100644 index 00000000..46ab7a4a --- /dev/null +++ b/spec/models/ci/step_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Ci::Step, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end