Change branch_name param to branch throughout V4 API
This commit is contained in:
parent
51546e26d7
commit
c79bbe26ab
17 changed files with 1255 additions and 53 deletions
|
@ -55,7 +55,7 @@ module Files
|
||||||
file_path = action[:file_path]
|
file_path = action[:file_path]
|
||||||
file_path = action[:previous_path] if action[:action] == :move
|
file_path = action[:previous_path] if action[:action] == :move
|
||||||
|
|
||||||
blob = repository.blob_at_branch(params[:branch_name], file_path)
|
blob = repository.blob_at_branch(params[:branch], file_path)
|
||||||
|
|
||||||
unless blob
|
unless blob
|
||||||
raise_error("File to be #{action[:action]}d `#{file_path}` does not exist.")
|
raise_error("File to be #{action[:action]}d `#{file_path}` does not exist.")
|
||||||
|
@ -89,7 +89,7 @@ module Files
|
||||||
def validate_create(action)
|
def validate_create(action)
|
||||||
return if project.empty_repo?
|
return if project.empty_repo?
|
||||||
|
|
||||||
if repository.blob_at_branch(params[:branch_name], action[:file_path])
|
if repository.blob_at_branch(params[:branch], action[:file_path])
|
||||||
raise_error("Your changes could not be committed because a file with the name `#{action[:file_path]}` already exists.")
|
raise_error("Your changes could not be committed because a file with the name `#{action[:file_path]}` already exists.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -102,14 +102,14 @@ module Files
|
||||||
raise_error("You must supply the original file path when moving file `#{action[:file_path]}`.")
|
raise_error("You must supply the original file path when moving file `#{action[:file_path]}`.")
|
||||||
end
|
end
|
||||||
|
|
||||||
blob = repository.blob_at_branch(params[:branch_name], action[:file_path])
|
blob = repository.blob_at_branch(params[:branch], action[:file_path])
|
||||||
|
|
||||||
if blob
|
if blob
|
||||||
raise_error("Move destination `#{action[:file_path]}` already exists.")
|
raise_error("Move destination `#{action[:file_path]}` already exists.")
|
||||||
end
|
end
|
||||||
|
|
||||||
if action[:content].nil?
|
if action[:content].nil?
|
||||||
blob = repository.blob_at_branch(params[:branch_name], action[:previous_path])
|
blob = repository.blob_at_branch(params[:branch], action[:previous_path])
|
||||||
blob.load_all_data!(repository) if blob.truncated?
|
blob.load_all_data!(repository) if blob.truncated?
|
||||||
params[:actions][index][:content] = blob.data
|
params[:actions][index][:content] = blob.data
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Standardize branch name params as branch on V4 API
|
||||||
|
merge_request: 8936
|
||||||
|
author:
|
|
@ -193,11 +193,11 @@ POST /projects/:id/repository/branches
|
||||||
| Attribute | Type | Required | Description |
|
| Attribute | Type | Required | Description |
|
||||||
| --------- | ---- | -------- | ----------- |
|
| --------- | ---- | -------- | ----------- |
|
||||||
| `id` | integer | yes | The ID of a project |
|
| `id` | integer | yes | The ID of a project |
|
||||||
| `branch_name` | string | yes | The name of the branch |
|
| `branch` | string | yes | The name of the branch |
|
||||||
| `ref` | string | yes | The branch name or commit SHA to create branch from |
|
| `ref` | string | yes | The branch name or commit SHA to create branch from |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/repository/branches?branch_name=newbranch&ref=master"
|
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/repository/branches?branch=newbranch&ref=master"
|
||||||
```
|
```
|
||||||
|
|
||||||
Example response:
|
Example response:
|
||||||
|
|
|
@ -69,7 +69,7 @@ POST /projects/:id/repository/commits
|
||||||
| Attribute | Type | Required | Description |
|
| Attribute | Type | Required | Description |
|
||||||
| --------- | ---- | -------- | ----------- |
|
| --------- | ---- | -------- | ----------- |
|
||||||
| `id` | integer/string | yes | The ID of a project or NAMESPACE/PROJECT_NAME |
|
| `id` | integer/string | yes | The ID of a project or NAMESPACE/PROJECT_NAME |
|
||||||
| `branch_name` | string | yes | The name of a branch |
|
| `branch` | string | yes | The name of a branch |
|
||||||
| `commit_message` | string | yes | Commit message |
|
| `commit_message` | string | yes | Commit message |
|
||||||
| `actions[]` | array | yes | An array of action hashes to commit as a batch. See the next table for what attributes it can take. |
|
| `actions[]` | array | yes | An array of action hashes to commit as a batch. See the next table for what attributes it can take. |
|
||||||
| `author_email` | string | no | Specify the commit author's email address |
|
| `author_email` | string | no | Specify the commit author's email address |
|
||||||
|
@ -87,7 +87,7 @@ POST /projects/:id/repository/commits
|
||||||
```bash
|
```bash
|
||||||
PAYLOAD=$(cat << 'JSON'
|
PAYLOAD=$(cat << 'JSON'
|
||||||
{
|
{
|
||||||
"branch_name": "master",
|
"branch": "master",
|
||||||
"commit_message": "some commit message",
|
"commit_message": "some commit message",
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,22 +46,22 @@ POST /projects/:id/repository/files
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --request POST --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v3/projects/13083/repository/files?file_path=app/project.rb&branch_name=master&author_email=author%40example.com&author_name=Firstname%20Lastname&content=some%20content&commit_message=create%20a%20new%20file'
|
curl --request POST --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v3/projects/13083/repository/files?file_path=app/project.rb&branch=master&author_email=author%40example.com&author_name=Firstname%20Lastname&content=some%20content&commit_message=create%20a%20new%20file'
|
||||||
```
|
```
|
||||||
|
|
||||||
Example response:
|
Example response:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"file_path": "app/project.rb",
|
"file_name": "app/project.rb",
|
||||||
"branch_name": "master"
|
"branch": "master"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
|
||||||
- `file_path` (required) - Full path to new file. Ex. lib/class.rb
|
- `file_path` (required) - Full path to new file. Ex. lib/class.rb
|
||||||
- `branch_name` (required) - The name of branch
|
- `branch` (required) - The name of branch
|
||||||
- `encoding` (optional) - Change encoding to 'base64'. Default is text.
|
- `encoding` (optional) - Change encoding to 'base64'. Default is text.
|
||||||
- `author_email` (optional) - Specify the commit author's email address
|
- `author_email` (optional) - Specify the commit author's email address
|
||||||
- `author_name` (optional) - Specify the commit author's name
|
- `author_name` (optional) - Specify the commit author's name
|
||||||
|
@ -75,22 +75,22 @@ PUT /projects/:id/repository/files
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --request PUT --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v3/projects/13083/repository/files?file_path=app/project.rb&branch_name=master&author_email=author%40example.com&author_name=Firstname%20Lastname&content=some%20other%20content&commit_message=update%20file'
|
curl --request PUT --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v3/projects/13083/repository/files?file_path=app/project.rb&branch=master&author_email=author%40example.com&author_name=Firstname%20Lastname&content=some%20other%20content&commit_message=update%20file'
|
||||||
```
|
```
|
||||||
|
|
||||||
Example response:
|
Example response:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"file_path": "app/project.rb",
|
"file_name": "app/project.rb",
|
||||||
"branch_name": "master"
|
"branch": "master"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
|
||||||
- `file_path` (required) - Full path to file. Ex. lib/class.rb
|
- `file_path` (required) - Full path to file. Ex. lib/class.rb
|
||||||
- `branch_name` (required) - The name of branch
|
- `branch` (required) - The name of branch
|
||||||
- `encoding` (optional) - Change encoding to 'base64'. Default is text.
|
- `encoding` (optional) - Change encoding to 'base64'. Default is text.
|
||||||
- `author_email` (optional) - Specify the commit author's email address
|
- `author_email` (optional) - Specify the commit author's email address
|
||||||
- `author_name` (optional) - Specify the commit author's name
|
- `author_name` (optional) - Specify the commit author's name
|
||||||
|
@ -113,22 +113,22 @@ DELETE /projects/:id/repository/files
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --request DELETE --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v3/projects/13083/repository/files?file_path=app/project.rb&branch_name=master&author_email=author%40example.com&author_name=Firstname%20Lastname&commit_message=delete%20file'
|
curl --request DELETE --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v3/projects/13083/repository/files?file_path=app/project.rb&branch=master&author_email=author%40example.com&author_name=Firstname%20Lastname&commit_message=delete%20file'
|
||||||
```
|
```
|
||||||
|
|
||||||
Example response:
|
Example response:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"file_path": "app/project.rb",
|
"file_name": "app/project.rb",
|
||||||
"branch_name": "master"
|
"branch": "master"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
|
||||||
- `file_path` (required) - Full path to file. Ex. lib/class.rb
|
- `file_path` (required) - Full path to file. Ex. lib/class.rb
|
||||||
- `branch_name` (required) - The name of branch
|
- `branch` (required) - The name of branch
|
||||||
- `author_email` (optional) - Specify the commit author's email address
|
- `author_email` (optional) - Specify the commit author's email address
|
||||||
- `author_name` (optional) - Specify the commit author's name
|
- `author_name` (optional) - Specify the commit author's name
|
||||||
- `commit_message` (required) - Commit message
|
- `commit_message` (required) - Commit message
|
||||||
|
|
|
@ -30,3 +30,9 @@ changes are in V4:
|
||||||
- Removed `DELETE projects/:id/deploy_keys/:key_id/disable`. Use `DELETE projects/:id/deploy_keys/:key_id` instead
|
- Removed `DELETE projects/:id/deploy_keys/:key_id/disable`. Use `DELETE projects/:id/deploy_keys/:key_id` instead
|
||||||
- Moved `PUT /users/:id/(block|unblock)` to `POST /users/:id/(block|unblock)`
|
- Moved `PUT /users/:id/(block|unblock)` to `POST /users/:id/(block|unblock)`
|
||||||
- Labels filter on `projects/:id/issues` and `/issues` now matches only issues containing all labels (i.e.: Logical AND, not OR)
|
- Labels filter on `projects/:id/issues` and `/issues` now matches only issues containing all labels (i.e.: Logical AND, not OR)
|
||||||
|
- Renamed param `branch_name` to `branch` on the following endpoints
|
||||||
|
- POST `:id/repository/branches`
|
||||||
|
- POST `:id/repository/commits`
|
||||||
|
- POST/PUT/DELETE `:id/repository/files`
|
||||||
|
- Renamed `branch_name` to `branch` on DELETE `id/repository/branches/:branch` response
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ module API
|
||||||
version 'v3', using: :path do
|
version 'v3', using: :path do
|
||||||
mount ::API::V3::Boards
|
mount ::API::V3::Boards
|
||||||
mount ::API::V3::Branches
|
mount ::API::V3::Branches
|
||||||
|
mount ::API::V3::Commits
|
||||||
mount ::API::V3::DeployKeys
|
mount ::API::V3::DeployKeys
|
||||||
|
mount ::API::V3::Files
|
||||||
mount ::API::V3::Issues
|
mount ::API::V3::Issues
|
||||||
mount ::API::V3::Labels
|
mount ::API::V3::Labels
|
||||||
mount ::API::V3::Members
|
mount ::API::V3::Members
|
||||||
|
|
|
@ -97,13 +97,13 @@ module API
|
||||||
success Entities::RepoBranch
|
success Entities::RepoBranch
|
||||||
end
|
end
|
||||||
params do
|
params do
|
||||||
requires :branch_name, type: String, desc: 'The name of the branch'
|
requires :branch, type: String, desc: 'The name of the branch'
|
||||||
requires :ref, type: String, desc: 'Create branch from commit sha or existing branch'
|
requires :ref, type: String, desc: 'Create branch from commit sha or existing branch'
|
||||||
end
|
end
|
||||||
post ":id/repository/branches" do
|
post ":id/repository/branches" do
|
||||||
authorize_push_project
|
authorize_push_project
|
||||||
result = CreateBranchService.new(user_project, current_user).
|
result = CreateBranchService.new(user_project, current_user).
|
||||||
execute(params[:branch_name], params[:ref])
|
execute(params[:branch], params[:ref])
|
||||||
|
|
||||||
if result[:status] == :success
|
if result[:status] == :success
|
||||||
present result[:branch],
|
present result[:branch],
|
||||||
|
@ -126,7 +126,7 @@ module API
|
||||||
|
|
||||||
if result[:status] == :success
|
if result[:status] == :success
|
||||||
{
|
{
|
||||||
branch_name: params[:branch]
|
branch: params[:branch]
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
render_api_error!(result[:message], result[:return_code])
|
render_api_error!(result[:message], result[:return_code])
|
||||||
|
|
|
@ -41,7 +41,7 @@ module API
|
||||||
detail 'This feature was introduced in GitLab 8.13'
|
detail 'This feature was introduced in GitLab 8.13'
|
||||||
end
|
end
|
||||||
params do
|
params do
|
||||||
requires :branch_name, type: String, desc: 'The name of branch'
|
requires :branch, type: String, desc: 'The name of branch'
|
||||||
requires :commit_message, type: String, desc: 'Commit message'
|
requires :commit_message, type: String, desc: 'Commit message'
|
||||||
requires :actions, type: Array[Hash], desc: 'Actions to perform in commit'
|
requires :actions, type: Array[Hash], desc: 'Actions to perform in commit'
|
||||||
optional :author_email, type: String, desc: 'Author email for commit'
|
optional :author_email, type: String, desc: 'Author email for commit'
|
||||||
|
@ -50,9 +50,8 @@ module API
|
||||||
post ":id/repository/commits" do
|
post ":id/repository/commits" do
|
||||||
authorize! :push_code, user_project
|
authorize! :push_code, user_project
|
||||||
|
|
||||||
attrs = declared_params
|
attrs = declared_params.merge(start_branch: declared_params[:branch], target_branch: declared_params[:branch])
|
||||||
attrs[:start_branch] = attrs[:branch_name]
|
|
||||||
attrs[:target_branch] = attrs[:branch_name]
|
|
||||||
attrs[:actions].map! do |action|
|
attrs[:actions].map! do |action|
|
||||||
action[:action] = action[:action].to_sym
|
action[:action] = action[:action].to_sym
|
||||||
action[:file_path].slice!(0) if action[:file_path] && action[:file_path].start_with?('/')
|
action[:file_path].slice!(0) if action[:file_path] && action[:file_path].start_with?('/')
|
||||||
|
|
|
@ -4,8 +4,8 @@ module API
|
||||||
def commit_params(attrs)
|
def commit_params(attrs)
|
||||||
{
|
{
|
||||||
file_path: attrs[:file_path],
|
file_path: attrs[:file_path],
|
||||||
start_branch: attrs[:branch_name],
|
start_branch: attrs[:branch],
|
||||||
target_branch: attrs[:branch_name],
|
target_branch: attrs[:branch],
|
||||||
commit_message: attrs[:commit_message],
|
commit_message: attrs[:commit_message],
|
||||||
file_content: attrs[:content],
|
file_content: attrs[:content],
|
||||||
file_content_encoding: attrs[:encoding],
|
file_content_encoding: attrs[:encoding],
|
||||||
|
@ -17,13 +17,13 @@ module API
|
||||||
def commit_response(attrs)
|
def commit_response(attrs)
|
||||||
{
|
{
|
||||||
file_path: attrs[:file_path],
|
file_path: attrs[:file_path],
|
||||||
branch_name: attrs[:branch_name]
|
branch: attrs[:branch]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
params :simple_file_params do
|
params :simple_file_params do
|
||||||
requires :file_path, type: String, desc: 'The path to new file. Ex. lib/class.rb'
|
requires :file_path, type: String, desc: 'The path to new file. Ex. lib/class.rb'
|
||||||
requires :branch_name, type: String, desc: 'The name of branch'
|
requires :branch, type: String, desc: 'The name of branch'
|
||||||
requires :commit_message, type: String, desc: 'Commit Message'
|
requires :commit_message, type: String, desc: 'Commit Message'
|
||||||
optional :author_email, type: String, desc: 'The email of the author'
|
optional :author_email, type: String, desc: 'The email of the author'
|
||||||
optional :author_name, type: String, desc: 'The name of the author'
|
optional :author_name, type: String, desc: 'The name of the author'
|
||||||
|
|
205
lib/api/v3/commits.rb
Normal file
205
lib/api/v3/commits.rb
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
require 'mime/types'
|
||||||
|
|
||||||
|
module API
|
||||||
|
module V3
|
||||||
|
class Commits < Grape::API
|
||||||
|
include PaginationParams
|
||||||
|
|
||||||
|
before { authenticate! }
|
||||||
|
before { authorize! :download_code, user_project }
|
||||||
|
|
||||||
|
params do
|
||||||
|
requires :id, type: String, desc: 'The ID of a project'
|
||||||
|
end
|
||||||
|
resource :projects do
|
||||||
|
desc 'Get a project repository commits' do
|
||||||
|
success ::API::Entities::RepoCommit
|
||||||
|
end
|
||||||
|
params do
|
||||||
|
optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
|
||||||
|
optional :since, type: DateTime, desc: 'Only commits after or in this date will be returned'
|
||||||
|
optional :until, type: DateTime, desc: 'Only commits before or in this date will be returned'
|
||||||
|
optional :page, type: Integer, default: 0, desc: 'The page for pagination'
|
||||||
|
optional :per_page, type: Integer, default: 20, desc: 'The number of results per page'
|
||||||
|
optional :path, type: String, desc: 'The file path'
|
||||||
|
end
|
||||||
|
get ":id/repository/commits" do
|
||||||
|
ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
|
||||||
|
offset = params[:page] * params[:per_page]
|
||||||
|
|
||||||
|
commits = user_project.repository.commits(ref,
|
||||||
|
path: params[:path],
|
||||||
|
limit: params[:per_page],
|
||||||
|
offset: offset,
|
||||||
|
after: params[:since],
|
||||||
|
before: params[:until])
|
||||||
|
|
||||||
|
present commits, with: ::API::Entities::RepoCommit
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Commit multiple file changes as one commit' do
|
||||||
|
success ::API::Entities::RepoCommitDetail
|
||||||
|
detail 'This feature was introduced in GitLab 8.13'
|
||||||
|
end
|
||||||
|
params do
|
||||||
|
requires :branch_name, type: String, desc: 'The name of branch'
|
||||||
|
requires :commit_message, type: String, desc: 'Commit message'
|
||||||
|
requires :actions, type: Array[Hash], desc: 'Actions to perform in commit'
|
||||||
|
optional :author_email, type: String, desc: 'Author email for commit'
|
||||||
|
optional :author_name, type: String, desc: 'Author name for commit'
|
||||||
|
end
|
||||||
|
post ":id/repository/commits" do
|
||||||
|
authorize! :push_code, user_project
|
||||||
|
|
||||||
|
attrs = declared_params.dup
|
||||||
|
branch = attrs.delete(:branch_name)
|
||||||
|
attrs.merge!(branch: branch, start_branch: branch, target_branch: branch)
|
||||||
|
|
||||||
|
attrs[:actions].map! do |action|
|
||||||
|
action[:action] = action[:action].to_sym
|
||||||
|
action[:file_path].slice!(0) if action[:file_path] && action[:file_path].start_with?('/')
|
||||||
|
action[:previous_path].slice!(0) if action[:previous_path] && action[:previous_path].start_with?('/')
|
||||||
|
action
|
||||||
|
end
|
||||||
|
|
||||||
|
result = ::Files::MultiService.new(user_project, current_user, attrs).execute
|
||||||
|
|
||||||
|
if result[:status] == :success
|
||||||
|
commit_detail = user_project.repository.commits(result[:result], limit: 1).first
|
||||||
|
present commit_detail, with: ::API::Entities::RepoCommitDetail
|
||||||
|
else
|
||||||
|
render_api_error!(result[:message], 400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Get a specific commit of a project' do
|
||||||
|
success ::API::Entities::RepoCommitDetail
|
||||||
|
failure [[404, 'Not Found']]
|
||||||
|
end
|
||||||
|
params do
|
||||||
|
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
|
||||||
|
end
|
||||||
|
get ":id/repository/commits/:sha" do
|
||||||
|
commit = user_project.commit(params[:sha])
|
||||||
|
|
||||||
|
not_found! "Commit" unless commit
|
||||||
|
|
||||||
|
present commit, with: ::API::Entities::RepoCommitDetail
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Get the diff for a specific commit of a project' do
|
||||||
|
failure [[404, 'Not Found']]
|
||||||
|
end
|
||||||
|
params do
|
||||||
|
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
|
||||||
|
end
|
||||||
|
get ":id/repository/commits/:sha/diff" do
|
||||||
|
commit = user_project.commit(params[:sha])
|
||||||
|
|
||||||
|
not_found! "Commit" unless commit
|
||||||
|
|
||||||
|
commit.raw_diffs.to_a
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Get a commit's comments" do
|
||||||
|
success ::API::Entities::CommitNote
|
||||||
|
failure [[404, 'Not Found']]
|
||||||
|
end
|
||||||
|
params do
|
||||||
|
use :pagination
|
||||||
|
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
|
||||||
|
end
|
||||||
|
get ':id/repository/commits/:sha/comments' do
|
||||||
|
commit = user_project.commit(params[:sha])
|
||||||
|
|
||||||
|
not_found! 'Commit' unless commit
|
||||||
|
notes = Note.where(commit_id: commit.id).order(:created_at)
|
||||||
|
|
||||||
|
present paginate(notes), with: ::API::Entities::CommitNote
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Cherry pick commit into a branch' do
|
||||||
|
detail 'This feature was introduced in GitLab 8.15'
|
||||||
|
success ::API::Entities::RepoCommit
|
||||||
|
end
|
||||||
|
params do
|
||||||
|
requires :sha, type: String, desc: 'A commit sha to be cherry picked'
|
||||||
|
requires :branch, type: String, desc: 'The name of the branch'
|
||||||
|
end
|
||||||
|
post ':id/repository/commits/:sha/cherry_pick' do
|
||||||
|
authorize! :push_code, user_project
|
||||||
|
|
||||||
|
commit = user_project.commit(params[:sha])
|
||||||
|
not_found!('Commit') unless commit
|
||||||
|
|
||||||
|
branch = user_project.repository.find_branch(params[:branch])
|
||||||
|
not_found!('Branch') unless branch
|
||||||
|
|
||||||
|
commit_params = {
|
||||||
|
commit: commit,
|
||||||
|
create_merge_request: false,
|
||||||
|
source_project: user_project,
|
||||||
|
source_branch: commit.cherry_pick_branch_name,
|
||||||
|
target_branch: params[:branch]
|
||||||
|
}
|
||||||
|
|
||||||
|
result = ::Commits::CherryPickService.new(user_project, current_user, commit_params).execute
|
||||||
|
|
||||||
|
if result[:status] == :success
|
||||||
|
branch = user_project.repository.find_branch(params[:branch])
|
||||||
|
present user_project.repository.commit(branch.dereferenced_target), with: ::API::Entities::RepoCommit
|
||||||
|
else
|
||||||
|
render_api_error!(result[:message], 400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Post comment to commit' do
|
||||||
|
success ::API::Entities::CommitNote
|
||||||
|
end
|
||||||
|
params do
|
||||||
|
requires :sha, type: String, regexp: /\A\h{6,40}\z/, desc: "The commit's SHA"
|
||||||
|
requires :note, type: String, desc: 'The text of the comment'
|
||||||
|
optional :path, type: String, desc: 'The file path'
|
||||||
|
given :path do
|
||||||
|
requires :line, type: Integer, desc: 'The line number'
|
||||||
|
requires :line_type, type: String, values: ['new', 'old'], default: 'new', desc: 'The type of the line'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
post ':id/repository/commits/:sha/comments' do
|
||||||
|
commit = user_project.commit(params[:sha])
|
||||||
|
not_found! 'Commit' unless commit
|
||||||
|
|
||||||
|
opts = {
|
||||||
|
note: params[:note],
|
||||||
|
noteable_type: 'Commit',
|
||||||
|
commit_id: commit.id
|
||||||
|
}
|
||||||
|
|
||||||
|
if params[:path]
|
||||||
|
commit.raw_diffs(all_diffs: true).each do |diff|
|
||||||
|
next unless diff.new_path == params[:path]
|
||||||
|
lines = Gitlab::Diff::Parser.new.parse(diff.diff.each_line)
|
||||||
|
|
||||||
|
lines.each do |line|
|
||||||
|
next unless line.new_pos == params[:line] && line.type == params[:line_type]
|
||||||
|
break opts[:line_code] = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
break if opts[:line_code]
|
||||||
|
end
|
||||||
|
|
||||||
|
opts[:type] = LegacyDiffNote.name if opts[:line_code]
|
||||||
|
end
|
||||||
|
|
||||||
|
note = ::Notes::CreateService.new(user_project, current_user, opts).execute
|
||||||
|
|
||||||
|
if note.save
|
||||||
|
present note, with: ::API::Entities::CommitNote
|
||||||
|
else
|
||||||
|
render_api_error!("Failed to save note #{note.errors.messages}", 400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
138
lib/api/v3/files.rb
Normal file
138
lib/api/v3/files.rb
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
module API
|
||||||
|
module V3
|
||||||
|
class Files < Grape::API
|
||||||
|
helpers do
|
||||||
|
def commit_params(attrs)
|
||||||
|
{
|
||||||
|
file_path: attrs[:file_path],
|
||||||
|
start_branch: attrs[:branch],
|
||||||
|
target_branch: attrs[:branch],
|
||||||
|
commit_message: attrs[:commit_message],
|
||||||
|
file_content: attrs[:content],
|
||||||
|
file_content_encoding: attrs[:encoding],
|
||||||
|
author_email: attrs[:author_email],
|
||||||
|
author_name: attrs[:author_name]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def commit_response(attrs)
|
||||||
|
{
|
||||||
|
file_path: attrs[:file_path],
|
||||||
|
branch: attrs[:branch]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
params :simple_file_params do
|
||||||
|
requires :file_path, type: String, desc: 'The path to new file. Ex. lib/class.rb'
|
||||||
|
requires :branch_name, type: String, desc: 'The name of branch'
|
||||||
|
requires :commit_message, type: String, desc: 'Commit Message'
|
||||||
|
optional :author_email, type: String, desc: 'The email of the author'
|
||||||
|
optional :author_name, type: String, desc: 'The name of the author'
|
||||||
|
end
|
||||||
|
|
||||||
|
params :extended_file_params do
|
||||||
|
use :simple_file_params
|
||||||
|
requires :content, type: String, desc: 'File content'
|
||||||
|
optional :encoding, type: String, values: %w[base64], desc: 'File encoding'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
params do
|
||||||
|
requires :id, type: String, desc: 'The project ID'
|
||||||
|
end
|
||||||
|
resource :projects do
|
||||||
|
desc 'Get a file from repository'
|
||||||
|
params do
|
||||||
|
requires :file_path, type: String, desc: 'The path to the file. Ex. lib/class.rb'
|
||||||
|
requires :ref, type: String, desc: 'The name of branch, tag, or commit'
|
||||||
|
end
|
||||||
|
get ":id/repository/files" do
|
||||||
|
authorize! :download_code, user_project
|
||||||
|
|
||||||
|
commit = user_project.commit(params[:ref])
|
||||||
|
not_found!('Commit') unless commit
|
||||||
|
|
||||||
|
repo = user_project.repository
|
||||||
|
blob = repo.blob_at(commit.sha, params[:file_path])
|
||||||
|
not_found!('File') unless blob
|
||||||
|
|
||||||
|
blob.load_all_data!(repo)
|
||||||
|
status(200)
|
||||||
|
|
||||||
|
{
|
||||||
|
file_name: blob.name,
|
||||||
|
file_path: blob.path,
|
||||||
|
size: blob.size,
|
||||||
|
encoding: "base64",
|
||||||
|
content: Base64.strict_encode64(blob.data),
|
||||||
|
ref: params[:ref],
|
||||||
|
blob_id: blob.id,
|
||||||
|
commit_id: commit.id,
|
||||||
|
last_commit_id: repo.last_commit_id_for_path(commit.sha, params[:file_path])
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Create new file in repository'
|
||||||
|
params do
|
||||||
|
use :extended_file_params
|
||||||
|
end
|
||||||
|
post ":id/repository/files" do
|
||||||
|
authorize! :push_code, user_project
|
||||||
|
|
||||||
|
file_params = declared_params(include_missing: false)
|
||||||
|
file_params[:branch] = file_params.delete(:branch_name)
|
||||||
|
|
||||||
|
result = ::Files::CreateService.new(user_project, current_user, commit_params(file_params)).execute
|
||||||
|
|
||||||
|
if result[:status] == :success
|
||||||
|
status(201)
|
||||||
|
commit_response(file_params)
|
||||||
|
else
|
||||||
|
render_api_error!(result[:message], 400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Update existing file in repository'
|
||||||
|
params do
|
||||||
|
use :extended_file_params
|
||||||
|
end
|
||||||
|
put ":id/repository/files" do
|
||||||
|
authorize! :push_code, user_project
|
||||||
|
|
||||||
|
file_params = declared_params(include_missing: false)
|
||||||
|
file_params[:branch] = file_params.delete(:branch_name)
|
||||||
|
|
||||||
|
result = ::Files::UpdateService.new(user_project, current_user, commit_params(file_params)).execute
|
||||||
|
|
||||||
|
if result[:status] == :success
|
||||||
|
status(200)
|
||||||
|
commit_response(file_params)
|
||||||
|
else
|
||||||
|
http_status = result[:http_status] || 400
|
||||||
|
render_api_error!(result[:message], http_status)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Delete an existing file in repository'
|
||||||
|
params do
|
||||||
|
use :simple_file_params
|
||||||
|
end
|
||||||
|
delete ":id/repository/files" do
|
||||||
|
authorize! :push_code, user_project
|
||||||
|
|
||||||
|
file_params = declared_params(include_missing: false)
|
||||||
|
file_params[:branch] = file_params.delete(:branch_name)
|
||||||
|
|
||||||
|
result = ::Files::DestroyService.new(user_project, current_user, commit_params(file_params)).execute
|
||||||
|
|
||||||
|
if result[:status] == :success
|
||||||
|
status(200)
|
||||||
|
commit_response(file_params)
|
||||||
|
else
|
||||||
|
render_api_error!(result[:message], 400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -272,7 +272,7 @@ describe API::Branches, api: true do
|
||||||
describe "POST /projects/:id/repository/branches" do
|
describe "POST /projects/:id/repository/branches" do
|
||||||
it "creates a new branch" do
|
it "creates a new branch" do
|
||||||
post api("/projects/#{project.id}/repository/branches", user),
|
post api("/projects/#{project.id}/repository/branches", user),
|
||||||
branch_name: 'feature1',
|
branch: 'feature1',
|
||||||
ref: branch_sha
|
ref: branch_sha
|
||||||
|
|
||||||
expect(response).to have_http_status(201)
|
expect(response).to have_http_status(201)
|
||||||
|
@ -283,14 +283,14 @@ describe API::Branches, api: true do
|
||||||
|
|
||||||
it "denies for user without push access" do
|
it "denies for user without push access" do
|
||||||
post api("/projects/#{project.id}/repository/branches", user2),
|
post api("/projects/#{project.id}/repository/branches", user2),
|
||||||
branch_name: branch_name,
|
branch: branch_name,
|
||||||
ref: branch_sha
|
ref: branch_sha
|
||||||
expect(response).to have_http_status(403)
|
expect(response).to have_http_status(403)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns 400 if branch name is invalid' do
|
it 'returns 400 if branch name is invalid' do
|
||||||
post api("/projects/#{project.id}/repository/branches", user),
|
post api("/projects/#{project.id}/repository/branches", user),
|
||||||
branch_name: 'new design',
|
branch: 'new design',
|
||||||
ref: branch_sha
|
ref: branch_sha
|
||||||
expect(response).to have_http_status(400)
|
expect(response).to have_http_status(400)
|
||||||
expect(json_response['message']).to eq('Branch name is invalid')
|
expect(json_response['message']).to eq('Branch name is invalid')
|
||||||
|
@ -298,12 +298,12 @@ describe API::Branches, api: true do
|
||||||
|
|
||||||
it 'returns 400 if branch already exists' do
|
it 'returns 400 if branch already exists' do
|
||||||
post api("/projects/#{project.id}/repository/branches", user),
|
post api("/projects/#{project.id}/repository/branches", user),
|
||||||
branch_name: 'new_design1',
|
branch: 'new_design1',
|
||||||
ref: branch_sha
|
ref: branch_sha
|
||||||
expect(response).to have_http_status(201)
|
expect(response).to have_http_status(201)
|
||||||
|
|
||||||
post api("/projects/#{project.id}/repository/branches", user),
|
post api("/projects/#{project.id}/repository/branches", user),
|
||||||
branch_name: 'new_design1',
|
branch: 'new_design1',
|
||||||
ref: branch_sha
|
ref: branch_sha
|
||||||
expect(response).to have_http_status(400)
|
expect(response).to have_http_status(400)
|
||||||
expect(json_response['message']).to eq('Branch already exists')
|
expect(json_response['message']).to eq('Branch already exists')
|
||||||
|
@ -311,7 +311,7 @@ describe API::Branches, api: true do
|
||||||
|
|
||||||
it 'returns 400 if ref name is invalid' do
|
it 'returns 400 if ref name is invalid' do
|
||||||
post api("/projects/#{project.id}/repository/branches", user),
|
post api("/projects/#{project.id}/repository/branches", user),
|
||||||
branch_name: 'new_design3',
|
branch: 'new_design3',
|
||||||
ref: 'foo'
|
ref: 'foo'
|
||||||
expect(response).to have_http_status(400)
|
expect(response).to have_http_status(400)
|
||||||
expect(json_response['message']).to eq('Invalid reference name')
|
expect(json_response['message']).to eq('Invalid reference name')
|
||||||
|
@ -326,14 +326,14 @@ describe API::Branches, api: true do
|
||||||
it "removes branch" do
|
it "removes branch" do
|
||||||
delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
|
delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
expect(json_response['branch_name']).to eq(branch_name)
|
expect(json_response['branch']).to eq(branch_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "removes a branch with dots in the branch name" do
|
it "removes a branch with dots in the branch name" do
|
||||||
delete api("/projects/#{project.id}/repository/branches/with.1.2.3", user)
|
delete api("/projects/#{project.id}/repository/branches/with.1.2.3", user)
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
expect(json_response['branch_name']).to eq("with.1.2.3")
|
expect(json_response['branch']).to eq("with.1.2.3")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns 404 if branch not exists' do
|
it 'returns 404 if branch not exists' do
|
||||||
|
|
|
@ -107,7 +107,7 @@ describe API::Commits, api: true do
|
||||||
let(:message) { 'Created file' }
|
let(:message) { 'Created file' }
|
||||||
let!(:invalid_c_params) do
|
let!(:invalid_c_params) do
|
||||||
{
|
{
|
||||||
branch_name: 'master',
|
branch: 'master',
|
||||||
commit_message: message,
|
commit_message: message,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -120,7 +120,7 @@ describe API::Commits, api: true do
|
||||||
end
|
end
|
||||||
let!(:valid_c_params) do
|
let!(:valid_c_params) do
|
||||||
{
|
{
|
||||||
branch_name: 'master',
|
branch: 'master',
|
||||||
commit_message: message,
|
commit_message: message,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -162,7 +162,7 @@ describe API::Commits, api: true do
|
||||||
let(:message) { 'Deleted file' }
|
let(:message) { 'Deleted file' }
|
||||||
let!(:invalid_d_params) do
|
let!(:invalid_d_params) do
|
||||||
{
|
{
|
||||||
branch_name: 'markdown',
|
branch: 'markdown',
|
||||||
commit_message: message,
|
commit_message: message,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -174,7 +174,7 @@ describe API::Commits, api: true do
|
||||||
end
|
end
|
||||||
let!(:valid_d_params) do
|
let!(:valid_d_params) do
|
||||||
{
|
{
|
||||||
branch_name: 'markdown',
|
branch: 'markdown',
|
||||||
commit_message: message,
|
commit_message: message,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -203,7 +203,7 @@ describe API::Commits, api: true do
|
||||||
let(:message) { 'Moved file' }
|
let(:message) { 'Moved file' }
|
||||||
let!(:invalid_m_params) do
|
let!(:invalid_m_params) do
|
||||||
{
|
{
|
||||||
branch_name: 'feature',
|
branch: 'feature',
|
||||||
commit_message: message,
|
commit_message: message,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -217,7 +217,7 @@ describe API::Commits, api: true do
|
||||||
end
|
end
|
||||||
let!(:valid_m_params) do
|
let!(:valid_m_params) do
|
||||||
{
|
{
|
||||||
branch_name: 'feature',
|
branch: 'feature',
|
||||||
commit_message: message,
|
commit_message: message,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -248,7 +248,7 @@ describe API::Commits, api: true do
|
||||||
let(:message) { 'Updated file' }
|
let(:message) { 'Updated file' }
|
||||||
let!(:invalid_u_params) do
|
let!(:invalid_u_params) do
|
||||||
{
|
{
|
||||||
branch_name: 'master',
|
branch: 'master',
|
||||||
commit_message: message,
|
commit_message: message,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -261,7 +261,7 @@ describe API::Commits, api: true do
|
||||||
end
|
end
|
||||||
let!(:valid_u_params) do
|
let!(:valid_u_params) do
|
||||||
{
|
{
|
||||||
branch_name: 'master',
|
branch: 'master',
|
||||||
commit_message: message,
|
commit_message: message,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -291,7 +291,7 @@ describe API::Commits, api: true do
|
||||||
let(:message) { 'Multiple actions' }
|
let(:message) { 'Multiple actions' }
|
||||||
let!(:invalid_mo_params) do
|
let!(:invalid_mo_params) do
|
||||||
{
|
{
|
||||||
branch_name: 'master',
|
branch: 'master',
|
||||||
commit_message: message,
|
commit_message: message,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -319,7 +319,7 @@ describe API::Commits, api: true do
|
||||||
end
|
end
|
||||||
let!(:valid_mo_params) do
|
let!(:valid_mo_params) do
|
||||||
{
|
{
|
||||||
branch_name: 'master',
|
branch: 'master',
|
||||||
commit_message: message,
|
commit_message: message,
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -104,7 +104,7 @@ describe API::Files, api: true do
|
||||||
let(:valid_params) do
|
let(:valid_params) do
|
||||||
{
|
{
|
||||||
file_path: 'newfile.rb',
|
file_path: 'newfile.rb',
|
||||||
branch_name: 'master',
|
branch: 'master',
|
||||||
content: 'puts 8',
|
content: 'puts 8',
|
||||||
commit_message: 'Added newfile'
|
commit_message: 'Added newfile'
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ describe API::Files, api: true do
|
||||||
let(:valid_params) do
|
let(:valid_params) do
|
||||||
{
|
{
|
||||||
file_path: file_path,
|
file_path: file_path,
|
||||||
branch_name: 'master',
|
branch: 'master',
|
||||||
content: 'puts 8',
|
content: 'puts 8',
|
||||||
commit_message: 'Changed file'
|
commit_message: 'Changed file'
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,7 @@ describe API::Files, api: true do
|
||||||
let(:valid_params) do
|
let(:valid_params) do
|
||||||
{
|
{
|
||||||
file_path: file_path,
|
file_path: file_path,
|
||||||
branch_name: 'master',
|
branch: 'master',
|
||||||
commit_message: 'Changed file'
|
commit_message: 'Changed file'
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -241,7 +241,7 @@ describe API::Files, api: true do
|
||||||
let(:put_params) do
|
let(:put_params) do
|
||||||
{
|
{
|
||||||
file_path: file_path,
|
file_path: file_path,
|
||||||
branch_name: 'master',
|
branch: 'master',
|
||||||
content: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=',
|
content: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=',
|
||||||
commit_message: 'Binary file with a \n should not be touched',
|
commit_message: 'Binary file with a \n should not be touched',
|
||||||
encoding: 'base64'
|
encoding: 'base64'
|
||||||
|
|
578
spec/requests/api/v3/commits_spec.rb
Normal file
578
spec/requests/api/v3/commits_spec.rb
Normal file
|
@ -0,0 +1,578 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'mime/types'
|
||||||
|
|
||||||
|
describe API::V3::Commits, api: true do
|
||||||
|
include ApiHelpers
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:user2) { create(:user) }
|
||||||
|
let!(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
|
||||||
|
let!(:master) { create(:project_member, :master, user: user, project: project) }
|
||||||
|
let!(:guest) { create(:project_member, :guest, user: user2, project: project) }
|
||||||
|
let!(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') }
|
||||||
|
let!(:another_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'another comment on a commit') }
|
||||||
|
|
||||||
|
before { project.team << [user, :reporter] }
|
||||||
|
|
||||||
|
describe "List repository commits" do
|
||||||
|
context "authorized user" do
|
||||||
|
before { project.team << [user2, :reporter] }
|
||||||
|
|
||||||
|
it "returns project commits" do
|
||||||
|
commit = project.repository.commit
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json_response).to be_an Array
|
||||||
|
expect(json_response.first['id']).to eq(commit.id)
|
||||||
|
expect(json_response.first['committer_name']).to eq(commit.committer_name)
|
||||||
|
expect(json_response.first['committer_email']).to eq(commit.committer_email)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "unauthorized user" do
|
||||||
|
it "does not return project commits" do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits")
|
||||||
|
expect(response).to have_http_status(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "since optional parameter" do
|
||||||
|
it "returns project commits since provided parameter" do
|
||||||
|
commits = project.repository.commits("master")
|
||||||
|
since = commits.second.created_at
|
||||||
|
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits?since=#{since.utc.iso8601}", user)
|
||||||
|
|
||||||
|
expect(json_response.size).to eq 2
|
||||||
|
expect(json_response.first["id"]).to eq(commits.first.id)
|
||||||
|
expect(json_response.second["id"]).to eq(commits.second.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "until optional parameter" do
|
||||||
|
it "returns project commits until provided parameter" do
|
||||||
|
commits = project.repository.commits("master")
|
||||||
|
before = commits.second.created_at
|
||||||
|
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits?until=#{before.utc.iso8601}", user)
|
||||||
|
|
||||||
|
if commits.size >= 20
|
||||||
|
expect(json_response.size).to eq(20)
|
||||||
|
else
|
||||||
|
expect(json_response.size).to eq(commits.size - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(json_response.first["id"]).to eq(commits.second.id)
|
||||||
|
expect(json_response.second["id"]).to eq(commits.third.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "invalid xmlschema date parameters" do
|
||||||
|
it "returns an invalid parameter error message" do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits?since=invalid-date", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
expect(json_response['error']).to eq('since is invalid')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "path optional parameter" do
|
||||||
|
it "returns project commits matching provided path parameter" do
|
||||||
|
path = 'files/ruby/popen.rb'
|
||||||
|
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits?path=#{path}", user)
|
||||||
|
|
||||||
|
expect(json_response.size).to eq(3)
|
||||||
|
expect(json_response.first["id"]).to eq("570e7b2abdd848b95f2f578043fc23bd6f6fd24d")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Create a commit with multiple files and actions" do
|
||||||
|
let!(:url) { "/projects/#{project.id}/repository/commits" }
|
||||||
|
|
||||||
|
it 'returns a 403 unauthorized for user without permissions' do
|
||||||
|
post v3_api(url, user2)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(403)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a 400 bad request if no params are given' do
|
||||||
|
post v3_api(url, user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
context :create do
|
||||||
|
let(:message) { 'Created file' }
|
||||||
|
let!(:invalid_c_params) do
|
||||||
|
{
|
||||||
|
branch_name: 'master',
|
||||||
|
commit_message: message,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'create',
|
||||||
|
file_path: 'files/ruby/popen.rb',
|
||||||
|
content: 'puts 8'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let!(:valid_c_params) do
|
||||||
|
{
|
||||||
|
branch_name: 'master',
|
||||||
|
commit_message: message,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'create',
|
||||||
|
file_path: 'foo/bar/baz.txt',
|
||||||
|
content: 'puts 8'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'a new file in project repo' do
|
||||||
|
post v3_api(url, user), valid_c_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
expect(json_response['title']).to eq(message)
|
||||||
|
expect(json_response['committer_name']).to eq(user.name)
|
||||||
|
expect(json_response['committer_email']).to eq(user.email)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a 400 bad request if file exists' do
|
||||||
|
post v3_api(url, user), invalid_c_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with project path in URL' do
|
||||||
|
let(:url) { "/projects/#{project.namespace.path}%2F#{project.path}/repository/commits" }
|
||||||
|
|
||||||
|
it 'a new file in project repo' do
|
||||||
|
post v3_api(url, user), valid_c_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context :delete do
|
||||||
|
let(:message) { 'Deleted file' }
|
||||||
|
let!(:invalid_d_params) do
|
||||||
|
{
|
||||||
|
branch_name: 'markdown',
|
||||||
|
commit_message: message,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'delete',
|
||||||
|
file_path: 'doc/api/projects.md'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let!(:valid_d_params) do
|
||||||
|
{
|
||||||
|
branch_name: 'markdown',
|
||||||
|
commit_message: message,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'delete',
|
||||||
|
file_path: 'doc/api/users.md'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'an existing file in project repo' do
|
||||||
|
post v3_api(url, user), valid_d_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
expect(json_response['title']).to eq(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a 400 bad request if file does not exist' do
|
||||||
|
post v3_api(url, user), invalid_d_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context :move do
|
||||||
|
let(:message) { 'Moved file' }
|
||||||
|
let!(:invalid_m_params) do
|
||||||
|
{
|
||||||
|
branch_name: 'feature',
|
||||||
|
commit_message: message,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'move',
|
||||||
|
file_path: 'CHANGELOG',
|
||||||
|
previous_path: 'VERSION',
|
||||||
|
content: '6.7.0.pre'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let!(:valid_m_params) do
|
||||||
|
{
|
||||||
|
branch_name: 'feature',
|
||||||
|
commit_message: message,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'move',
|
||||||
|
file_path: 'VERSION.txt',
|
||||||
|
previous_path: 'VERSION',
|
||||||
|
content: '6.7.0.pre'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'an existing file in project repo' do
|
||||||
|
post v3_api(url, user), valid_m_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
expect(json_response['title']).to eq(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a 400 bad request if file does not exist' do
|
||||||
|
post v3_api(url, user), invalid_m_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context :update do
|
||||||
|
let(:message) { 'Updated file' }
|
||||||
|
let!(:invalid_u_params) do
|
||||||
|
{
|
||||||
|
branch_name: 'master',
|
||||||
|
commit_message: message,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'update',
|
||||||
|
file_path: 'foo/bar.baz',
|
||||||
|
content: 'puts 8'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let!(:valid_u_params) do
|
||||||
|
{
|
||||||
|
branch_name: 'master',
|
||||||
|
commit_message: message,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'update',
|
||||||
|
file_path: 'files/ruby/popen.rb',
|
||||||
|
content: 'puts 8'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'an existing file in project repo' do
|
||||||
|
post v3_api(url, user), valid_u_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
expect(json_response['title']).to eq(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a 400 bad request if file does not exist' do
|
||||||
|
post v3_api(url, user), invalid_u_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "multiple operations" do
|
||||||
|
let(:message) { 'Multiple actions' }
|
||||||
|
let!(:invalid_mo_params) do
|
||||||
|
{
|
||||||
|
branch_name: 'master',
|
||||||
|
commit_message: message,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'create',
|
||||||
|
file_path: 'files/ruby/popen.rb',
|
||||||
|
content: 'puts 8'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'delete',
|
||||||
|
file_path: 'doc/v3_api/projects.md'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'move',
|
||||||
|
file_path: 'CHANGELOG',
|
||||||
|
previous_path: 'VERSION',
|
||||||
|
content: '6.7.0.pre'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'update',
|
||||||
|
file_path: 'foo/bar.baz',
|
||||||
|
content: 'puts 8'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let!(:valid_mo_params) do
|
||||||
|
{
|
||||||
|
branch_name: 'master',
|
||||||
|
commit_message: message,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: 'create',
|
||||||
|
file_path: 'foo/bar/baz.txt',
|
||||||
|
content: 'puts 8'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'delete',
|
||||||
|
file_path: 'Gemfile.zip'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'move',
|
||||||
|
file_path: 'VERSION.txt',
|
||||||
|
previous_path: 'VERSION',
|
||||||
|
content: '6.7.0.pre'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'update',
|
||||||
|
file_path: 'files/ruby/popen.rb',
|
||||||
|
content: 'puts 8'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'are commited as one in project repo' do
|
||||||
|
post v3_api(url, user), valid_mo_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
expect(json_response['title']).to eq(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'return a 400 bad request if there are any issues' do
|
||||||
|
post v3_api(url, user), invalid_mo_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Get a single commit" do
|
||||||
|
context "authorized user" do
|
||||||
|
it "returns a commit by sha" do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json_response['id']).to eq(project.repository.commit.id)
|
||||||
|
expect(json_response['title']).to eq(project.repository.commit.title)
|
||||||
|
expect(json_response['stats']['additions']).to eq(project.repository.commit.stats.additions)
|
||||||
|
expect(json_response['stats']['deletions']).to eq(project.repository.commit.stats.deletions)
|
||||||
|
expect(json_response['stats']['total']).to eq(project.repository.commit.stats.total)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 404 error if not found" do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/invalid_sha", user)
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil for commit without CI" do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json_response['status']).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns status for CI" do
|
||||||
|
pipeline = project.ensure_pipeline('master', project.repository.commit.sha)
|
||||||
|
pipeline.update(status: 'success')
|
||||||
|
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json_response['status']).to eq(pipeline.status)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns status for CI when pipeline is created" do
|
||||||
|
project.ensure_pipeline('master', project.repository.commit.sha)
|
||||||
|
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json_response['status']).to eq("created")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "unauthorized user" do
|
||||||
|
it "does not return the selected commit" do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}")
|
||||||
|
expect(response).to have_http_status(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Get the diff of a commit" do
|
||||||
|
context "authorized user" do
|
||||||
|
before { project.team << [user2, :reporter] }
|
||||||
|
|
||||||
|
it "returns the diff of the selected commit" do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user)
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
|
||||||
|
expect(json_response).to be_an Array
|
||||||
|
expect(json_response.length).to be >= 1
|
||||||
|
expect(json_response.first.keys).to include "diff"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 404 error if invalid commit" do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/invalid_sha/diff", user)
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "unauthorized user" do
|
||||||
|
it "does not return the diff of the selected commit" do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff")
|
||||||
|
expect(response).to have_http_status(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Get the comments of a commit' do
|
||||||
|
context 'authorized user' do
|
||||||
|
it 'returns merge_request comments' do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user)
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json_response).to be_an Array
|
||||||
|
expect(json_response.length).to eq(2)
|
||||||
|
expect(json_response.first['note']).to eq('a comment on a commit')
|
||||||
|
expect(json_response.first['author']['id']).to eq(user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a 404 error if merge_request_id not found' do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/1234ab/comments", user)
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'unauthorized user' do
|
||||||
|
it 'does not return the diff of the selected commit' do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/commits/1234ab/comments")
|
||||||
|
expect(response).to have_http_status(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST :id/repository/commits/:sha/cherry_pick' do
|
||||||
|
let(:master_pickable_commit) { project.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') }
|
||||||
|
|
||||||
|
context 'authorized user' do
|
||||||
|
it 'cherry picks a commit' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'master'
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
expect(json_response['title']).to eq(master_pickable_commit.title)
|
||||||
|
expect(json_response['message']).to eq(master_pickable_commit.message)
|
||||||
|
expect(json_response['author_name']).to eq(master_pickable_commit.author_name)
|
||||||
|
expect(json_response['committer_name']).to eq(user.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 400 if commit is already included in the target branch' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'markdown'
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
expect(json_response['message']).to eq('Sorry, we cannot cherry-pick this commit automatically.
|
||||||
|
A cherry-pick may have already been performed with this commit, or a more recent commit may have updated some of its content.')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 400 if you are not allowed to push to the target branch' do
|
||||||
|
project.team << [user2, :developer]
|
||||||
|
protected_branch = create(:protected_branch, project: project, name: 'feature')
|
||||||
|
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user2), branch: protected_branch.name
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
expect(json_response['message']).to eq('You are not allowed to push into this branch')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 400 for missing parameters' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
expect(json_response['error']).to eq('branch is missing')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 404 if commit is not found' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/abcd0123/cherry_pick", user), branch: 'master'
|
||||||
|
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
expect(json_response['message']).to eq('404 Commit Not Found')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 404 if branch is not found' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'foo'
|
||||||
|
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
expect(json_response['message']).to eq('404 Branch Not Found')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 400 for missing parameters' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
expect(json_response['error']).to eq('branch is missing')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'unauthorized user' do
|
||||||
|
it 'does not cherry pick the commit' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick"), branch: 'master'
|
||||||
|
|
||||||
|
expect(response).to have_http_status(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Post comment to commit' do
|
||||||
|
context 'authorized user' do
|
||||||
|
it 'returns comment' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user), note: 'My comment'
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
expect(json_response['note']).to eq('My comment')
|
||||||
|
expect(json_response['path']).to be_nil
|
||||||
|
expect(json_response['line']).to be_nil
|
||||||
|
expect(json_response['line_type']).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the inline comment' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user), note: 'My comment', path: project.repository.commit.raw_diffs.first.new_path, line: 1, line_type: 'new'
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
expect(json_response['note']).to eq('My comment')
|
||||||
|
expect(json_response['path']).to eq(project.repository.commit.raw_diffs.first.new_path)
|
||||||
|
expect(json_response['line']).to eq(1)
|
||||||
|
expect(json_response['line_type']).to eq('new')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 400 if note is missing' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user)
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 404 if note is attached to non existent commit' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/1234ab/comments", user), note: 'My comment'
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'unauthorized user' do
|
||||||
|
it 'does not return the diff of the selected commit' do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments")
|
||||||
|
expect(response).to have_http_status(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
270
spec/requests/api/v3/files_spec.rb
Normal file
270
spec/requests/api/v3/files_spec.rb
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe API::V3::Files, api: true do
|
||||||
|
include ApiHelpers
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let!(:project) { create(:project, :repository, namespace: user.namespace ) }
|
||||||
|
let(:guest) { create(:user) { |u| project.add_guest(u) } }
|
||||||
|
let(:file_path) { 'files/ruby/popen.rb' }
|
||||||
|
let(:params) do
|
||||||
|
{
|
||||||
|
file_path: file_path,
|
||||||
|
ref: 'master'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let(:author_email) { FFaker::Internet.email }
|
||||||
|
|
||||||
|
# I have to remove periods from the end of the name
|
||||||
|
# This happened when the user's name had a suffix (i.e. "Sr.")
|
||||||
|
# This seems to be what git does under the hood. For example, this commit:
|
||||||
|
#
|
||||||
|
# $ git commit --author='Foo Sr. <foo@example.com>' -m 'Where's my trailing period?'
|
||||||
|
#
|
||||||
|
# results in this:
|
||||||
|
#
|
||||||
|
# $ git show --pretty
|
||||||
|
# ...
|
||||||
|
# Author: Foo Sr <foo@example.com>
|
||||||
|
# ...
|
||||||
|
let(:author_name) { FFaker::Name.name.chomp("\.") }
|
||||||
|
|
||||||
|
before { project.team << [user, :developer] }
|
||||||
|
|
||||||
|
describe "GET /projects/:id/repository/files" do
|
||||||
|
let(:route) { "/projects/#{project.id}/repository/files" }
|
||||||
|
|
||||||
|
shared_examples_for 'repository files' do
|
||||||
|
it "returns file info" do
|
||||||
|
get v3_api(route, current_user), params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json_response['file_path']).to eq(file_path)
|
||||||
|
expect(json_response['file_name']).to eq('popen.rb')
|
||||||
|
expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d')
|
||||||
|
expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when no params are given' do
|
||||||
|
it_behaves_like '400 response' do
|
||||||
|
let(:request) { get v3_api(route, current_user) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when file_path does not exist' do
|
||||||
|
let(:params) do
|
||||||
|
{
|
||||||
|
file_path: 'app/models/application.rb',
|
||||||
|
ref: 'master',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like '404 response' do
|
||||||
|
let(:request) { get v3_api(route, current_user), params }
|
||||||
|
let(:message) { '404 File Not Found' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when repository is disabled' do
|
||||||
|
include_context 'disabled repository'
|
||||||
|
|
||||||
|
it_behaves_like '403 response' do
|
||||||
|
let(:request) { get v3_api(route, current_user), params }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when unauthenticated', 'and project is public' do
|
||||||
|
it_behaves_like 'repository files' do
|
||||||
|
let(:project) { create(:project, :public) }
|
||||||
|
let(:current_user) { nil }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when unauthenticated', 'and project is private' do
|
||||||
|
it_behaves_like '404 response' do
|
||||||
|
let(:request) { get v3_api(route), params }
|
||||||
|
let(:message) { '404 Project Not Found' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when authenticated', 'as a developer' do
|
||||||
|
it_behaves_like 'repository files' do
|
||||||
|
let(:current_user) { user }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when authenticated', 'as a guest' do
|
||||||
|
it_behaves_like '403 response' do
|
||||||
|
let(:request) { get v3_api(route, guest), params }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /projects/:id/repository/files" do
|
||||||
|
let(:valid_params) do
|
||||||
|
{
|
||||||
|
file_path: 'newfile.rb',
|
||||||
|
branch_name: 'master',
|
||||||
|
content: 'puts 8',
|
||||||
|
commit_message: 'Added newfile'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a new file in project repo" do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/files", user), valid_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
expect(json_response['file_path']).to eq('newfile.rb')
|
||||||
|
last_commit = project.repository.commit.raw
|
||||||
|
expect(last_commit.author_email).to eq(user.email)
|
||||||
|
expect(last_commit.author_name).to eq(user.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 400 bad request if no params given" do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/files", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 400 if editor fails to create file" do
|
||||||
|
allow_any_instance_of(Repository).to receive(:commit_file).
|
||||||
|
and_return(false)
|
||||||
|
|
||||||
|
post v3_api("/projects/#{project.id}/repository/files", user), valid_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when specifying an author" do
|
||||||
|
it "creates a new file with the specified author" do
|
||||||
|
valid_params.merge!(author_email: author_email, author_name: author_name)
|
||||||
|
|
||||||
|
post v3_api("/projects/#{project.id}/repository/files", user), valid_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
|
last_commit = project.repository.commit.raw
|
||||||
|
expect(last_commit.author_email).to eq(author_email)
|
||||||
|
expect(last_commit.author_name).to eq(author_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "PUT /projects/:id/repository/files" do
|
||||||
|
let(:valid_params) do
|
||||||
|
{
|
||||||
|
file_path: file_path,
|
||||||
|
branch_name: 'master',
|
||||||
|
content: 'puts 8',
|
||||||
|
commit_message: 'Changed file'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "updates existing file in project repo" do
|
||||||
|
put v3_api("/projects/#{project.id}/repository/files", user), valid_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json_response['file_path']).to eq(file_path)
|
||||||
|
last_commit = project.repository.commit.raw
|
||||||
|
expect(last_commit.author_email).to eq(user.email)
|
||||||
|
expect(last_commit.author_name).to eq(user.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 400 bad request if no params given" do
|
||||||
|
put v3_api("/projects/#{project.id}/repository/files", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when specifying an author" do
|
||||||
|
it "updates a file with the specified author" do
|
||||||
|
valid_params.merge!(author_email: author_email, author_name: author_name, content: "New content")
|
||||||
|
|
||||||
|
put v3_api("/projects/#{project.id}/repository/files", user), valid_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
last_commit = project.repository.commit.raw
|
||||||
|
expect(last_commit.author_email).to eq(author_email)
|
||||||
|
expect(last_commit.author_name).to eq(author_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "DELETE /projects/:id/repository/files" do
|
||||||
|
let(:valid_params) do
|
||||||
|
{
|
||||||
|
file_path: file_path,
|
||||||
|
branch_name: 'master',
|
||||||
|
commit_message: 'Changed file'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deletes existing file in project repo" do
|
||||||
|
delete v3_api("/projects/#{project.id}/repository/files", user), valid_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json_response['file_path']).to eq(file_path)
|
||||||
|
last_commit = project.repository.commit.raw
|
||||||
|
expect(last_commit.author_email).to eq(user.email)
|
||||||
|
expect(last_commit.author_name).to eq(user.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 400 bad request if no params given" do
|
||||||
|
delete v3_api("/projects/#{project.id}/repository/files", user)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 400 if fails to create file" do
|
||||||
|
allow_any_instance_of(Repository).to receive(:remove_file).and_return(false)
|
||||||
|
|
||||||
|
delete v3_api("/projects/#{project.id}/repository/files", user), valid_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when specifying an author" do
|
||||||
|
it "removes a file with the specified author" do
|
||||||
|
valid_params.merge!(author_email: author_email, author_name: author_name)
|
||||||
|
|
||||||
|
delete v3_api("/projects/#{project.id}/repository/files", user), valid_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
last_commit = project.repository.commit.raw
|
||||||
|
expect(last_commit.author_email).to eq(author_email)
|
||||||
|
expect(last_commit.author_name).to eq(author_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /projects/:id/repository/files with binary file" do
|
||||||
|
let(:file_path) { 'test.bin' }
|
||||||
|
let(:put_params) do
|
||||||
|
{
|
||||||
|
file_path: file_path,
|
||||||
|
branch_name: 'master',
|
||||||
|
content: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=',
|
||||||
|
commit_message: 'Binary file with a \n should not be touched',
|
||||||
|
encoding: 'base64'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let(:get_params) do
|
||||||
|
{
|
||||||
|
file_path: file_path,
|
||||||
|
ref: 'master',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
post v3_api("/projects/#{project.id}/repository/files", user), put_params
|
||||||
|
end
|
||||||
|
|
||||||
|
it "remains unchanged" do
|
||||||
|
get v3_api("/projects/#{project.id}/repository/files", user), get_params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(json_response['file_path']).to eq(file_path)
|
||||||
|
expect(json_response['file_name']).to eq(file_path)
|
||||||
|
expect(json_response['content']).to eq(put_params[:content])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue