From 2ddaf0038710d057e96f8211036399aa65d3ddb4 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Mon, 28 Jan 2013 14:49:27 +0100 Subject: [PATCH 01/49] Added documentation for passing the token as header The documentation was unclear about how to pass the api private token as header. Updated the doc to include the nessesary information bits and added an example using the curl command line client. --- doc/api/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/api/README.md b/doc/api/README.md index 477429c9..881d4ab6 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -1,6 +1,6 @@ # GitLab API -All API requests require authentication. You need to pass a `private_token` parameter by url or header. You can find or reset your private token in your profile. +All API requests require authentication. You need to pass a `private_token` parameter by url or header. If passed as header, the header name must be "PRIVATE-TOKEN" (capital and with dash instead of underscore). You can find or reset your private token in your profile. If no, or an invalid, `private_token` is provided then an error message will be returned with status code 401: @@ -18,6 +18,13 @@ Example of a valid API request: GET http://example.com/api/v3/projects?private_token=QVy1PB7sTxfy4pqfZM1U ``` +Example for a valid API request using curl and authentication via header: + +``` +curl --header "PRIVATE-TOKEN: QVy1PB7sTxfy4pqfZM1U" "http://example.com/api/v3/projects" +``` + + The API uses JSON to serialize data. You don't need to specify `.json` at the end of API URL. #### Pagination From a90d5c21b55584572ff22d7a3affd84cd19d38d2 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Mon, 28 Jan 2013 16:46:58 +0100 Subject: [PATCH 02/49] describe the project access level the documentation mentions access_level as required parameter, but fails to list accepted values. --- doc/api/projects.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index 41128675..e8730173 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -107,6 +107,18 @@ Parameters: Will return created project with status `201 Created` on success, or `404 Not found` on fail. +## Project access levels + +The project access levels are defined in the `user_project` class. Currently, 4 +levels are recoginized: + +``` + GUEST = 10 + REPORTER = 20 + DEVELOPER = 30 + MASTER = 40 +``` + ## List project team members Get a list of project team members. From e76215a395bb814972c1385ce815b2da2a6e3402 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Mon, 28 Jan 2013 23:51:45 +0100 Subject: [PATCH 03/49] Update docs to reflect that project names are allowed as ID The API accepts project names in all places where project IDs are expected. Updated the docs to reflect that. --- doc/api/projects.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index e8730173..64d79a0d 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -53,7 +53,8 @@ GET /projects ## Single project -Get a specific project, identified by project ID, which is owned by the authentication user. +Get a specific project, identified by project ID or NAME, which is owned by the authentication user. +Currently namespaced projects cannot retrieved by name. ``` GET /projects/:id @@ -61,7 +62,7 @@ GET /projects/:id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project ```json { @@ -129,7 +130,7 @@ GET /projects/:id/members Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `query` - Query string ## Get project team member @@ -142,7 +143,7 @@ GET /projects/:id/members/:user_id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `user_id` (required) - The ID of a user ```json @@ -168,7 +169,7 @@ POST /projects/:id/members Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `user_id` (required) - The ID of a user to add + `access_level` (required) - Project access level @@ -184,7 +185,7 @@ PUT /projects/:id/members/:user_id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `user_id` (required) - The ID of a team member + `access_level` (required) - Project access level @@ -200,7 +201,7 @@ DELETE /projects/:id/members/:user_id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `user_id` (required) - The ID of a team member Status code `200` will be returned on success. @@ -215,7 +216,7 @@ GET /projects/:id/hooks Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project Will return hooks with status `200 OK` on success, or `404 Not found` on fail. @@ -229,7 +230,7 @@ GET /projects/:id/hooks/:hook_id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `hook_id` (required) - The ID of a project hook Will return hook with status `200 OK` on success, or `404 Not found` on fail. @@ -244,7 +245,7 @@ POST /projects/:id/hooks Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `url` (required) - The hook URL Will return status `201 Created` on success, or `404 Not found` on fail. @@ -259,7 +260,7 @@ PUT /projects/:id/hooks/:hook_id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `hook_id` (required) - The ID of a project hook + `url` (required) - The hook URL @@ -276,7 +277,7 @@ DELETE /projects/:id/hooks Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `hook_id` (required) - The ID of hook to delete Will return status `200 OK` on success, or `404 Not found` on fail. From 2a669fc89997376af1e76bf3ed574d948009c5b2 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Tue, 29 Jan 2013 18:20:59 +0100 Subject: [PATCH 04/49] rescue all errors and return the proper format This rescues all errors and returns a proper JSON response. Fixes #2833. --- lib/api.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/api.rb b/lib/api.rb index f58b82ff..3dd82715 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -8,6 +8,10 @@ module Gitlab rack_response({'message' => '404 Not found'}.to_json, 404) end + rescue_from :all do + rack_response({'message' => '500 Internal Server Error'}, 500) + end + format :json error_format :json helpers APIHelpers From c72910a8bf782c10662dd4392e81ef6408f801ee Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Fri, 1 Feb 2013 09:42:02 +0000 Subject: [PATCH 05/49] log fatal errors that we catch In case we rescue from a fatal error, we want the error and the backtrace to the error logged, so we can debug later on. This change injects the configured logger from the rails app to the grape API and logs error as well as backtrace in a rails-like fashion. --- config/routes.rb | 1 + lib/api.rb | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 7ffa081a..66cb62bc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,6 +8,7 @@ Gitlab::Application.routes.draw do # API require 'api' + Gitlab::API.logger Rails.logger mount Gitlab::API => '/api' constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.admin? } diff --git a/lib/api.rb b/lib/api.rb index 3dd82715..15d99cc7 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -8,7 +8,16 @@ module Gitlab rack_response({'message' => '404 Not found'}.to_json, 404) end - rescue_from :all do + rescue_from :all do |exception| + # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60 + # why is this not wrapped in something reusable? + trace = exception.backtrace + + message = "\n#{exception.class} (#{exception.message}):\n" + message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) + message << " " << trace.join("\n ") + + API.logger.add Logger::FATAL, message rack_response({'message' => '500 Internal Server Error'}, 500) end From ce6436b98a8a86356ee93e6eaf136d27d7f77b93 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Fri, 1 Feb 2013 13:53:35 +0000 Subject: [PATCH 06/49] Don't crash when removing a user that's not project member The attempt to revoke project access for a user that was not member of the project results in a 500 Internal Server error where it actually should result in a 200 OK since after the operation, the user is not member of the project. This turns the operation into an idempotent call that can be repeated with no ill effects. Updated the spec and changed the code accordingly. However, the result differs slightly, as we can't return the users project access level if the user was not member. I'm not aware if anybody relies on the result of this call. Fixes #2832 --- lib/api/projects.rb | 6 +++++- spec/requests/api/projects_spec.rb | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index cbef1ed3..5444ba6a 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -132,7 +132,11 @@ module Gitlab delete ":id/members/:user_id" do authorize! :admin_project, user_project users_project = user_project.users_projects.find_by_user_id params[:user_id] - users_project.destroy + unless users_project.nil? + users_project.destroy + else + {:message => "Access revoked", :id => params[:user_id].to_i} + end end # Get project hooks diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index c2244210..8351b4bf 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -167,6 +167,17 @@ describe Gitlab::API do end end + describe "DELETE /projects/:id/members/:user_id" do + it "should return 200 OK when the user was not member" do + expect { + delete api("/projects/#{project.id}/members/1000000", user) + }.to change { UsersProject.count }.by(0) + response.status.should == 200 + json_response['message'].should == "Access revoked" + json_response['id'].should == 1000000 + end + end + describe "GET /projects/:id/hooks" do it "should return project hooks" do get api("/projects/#{project.id}/hooks", user) From 566de5ab06d1c29ac632d2fbd0f4440788fe1339 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Fri, 1 Feb 2013 14:20:51 +0000 Subject: [PATCH 07/49] update api documentation for delete team member correctly describes the new behavior --- doc/api/projects.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 41128675..704671a2 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -191,7 +191,10 @@ Parameters: + `id` (required) - The ID of a project + `user_id` (required) - The ID of a team member -Status code `200` will be returned on success. +Status code `200 OK` will be returned on success. This method is idempotent and call be called multiple +times with the same parameters. Revoking team membership for a user who is not currently a team member is +considered success. Please note that the returned JSON currently differs slightly. Thus you should not +rely on the returned JSON structure. ## List project hooks @@ -215,7 +218,7 @@ Get hook for project GET /projects/:id/hooks/:hook_id ``` -Parameters: +Parameters:ยง + `id` (required) - The ID of a project + `hook_id` (required) - The ID of a project hook From 413952ff944d10164d9d08a8a48e7725fe44b1b3 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 5 Feb 2013 17:13:47 +0100 Subject: [PATCH 08/49] Creating or updating a MR returns more informative status codes. Using the API library to create or update a merge request at the moment a 404 error is returned. This is fine when the merge request in question does not exist, but does not provide good information that for example a required attribute is missing. A status code of 400 (Bad request) is returned when creating or updating a merge request when either `source_branch` or `target_branch` is missing. A status code of 409 is returned when `source_branch` and `target_branch` are the same. Tests are added for these cases. --- lib/api/merge_requests.rb | 14 +++++++++++ spec/requests/api/merge_requests_spec.rb | 30 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 470cd1e1..25ee8f05 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -60,6 +60,13 @@ module Gitlab merge_request.reload_code present merge_request, with: Entities::MergeRequest else + if merge_request.errors[:target_branch].any? + error!(merge_request.errors[:target_branch], 400) + elsif merge_request.errors[:source_branch].any? + error!(merge_request.errors[:source_branch], 400) + elsif merge_request.errors[:base].any? + error!(merge_request.errors[:base], 422) + end not_found! end end @@ -88,6 +95,13 @@ module Gitlab merge_request.mark_as_unchecked present merge_request, with: Entities::MergeRequest else + if merge_request.errors[:target_branch].any? + error!(merge_request.errors[:target_branch], 400) + elsif merge_request.errors[:source_branch].any? + error!(merge_request.errors[:source_branch], 400) + elsif merge_request.errors[:base].any? + error!(merge_request.errors[:base], 422) + end not_found! end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 5da54154..bf87ecbd 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -41,6 +41,24 @@ describe Gitlab::API do response.status.should == 201 json_response['title'].should == 'Test merge_request' end + + it "should return 422 when source_branch equals target_branch" do + post api("/projects/#{project.id}/merge_requests", user), + title: "Test merge_request", source_branch: "master", target_branch: "master", author: user + response.status.should == 422 + end + + it "should return 400 when source_branch is missing" do + post api("/projects/#{project.id}/merge_requests", user), + title: "Test merge_request", target_branch: "master", author: user + response.status.should == 400 + end + + it "should return 400 when target_branch is missing" do + post api("/projects/#{project.id}/merge_requests", user), + title: "Test merge_request", source_branch: "stable", author: user + response.status.should == 400 + end end describe "PUT /projects/:id/merge_request/:merge_request_id" do @@ -49,6 +67,18 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == 'New title' end + + it "should return 422 when source_branch and target_branch are renamed the same" do + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), + source_branch: "master", target_branch: "master" + response.status.should == 422 + end + + it "should return merge_request with renamed target_branch" do + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), target_branch: "test" + response.status.should == 200 + json_response['target_branch'].should == 'test' + end end describe "POST /projects/:id/merge_request/:merge_request_id/comments" do From 3f4e215c804f13def585dea995efa29b2af266ec Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 5 Feb 2013 18:36:36 +0100 Subject: [PATCH 09/49] Extracted helper method to avoid code duplication --- lib/api/merge_requests.rb | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 25ee8f05..ec63b352 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -5,6 +5,23 @@ module Gitlab resource :projects do + helpers do + # If an error occurred this helper method provides an appropriate status code + # + # Parameters: + # merge_request_errors (required) - The errors collection of MR + # + def handle_merge_request_error(merge_request_errors) + if merge_request_errors[:target_branch].any? + error!(merge_request_errors[:target_branch], 400) + elsif merge_request_errors[:source_branch].any? + error!(merge_request_errors[:source_branch], 400) + elsif merge_request_errors[:base].any? + error!(merge_request_errors[:base], 422) + end + end + end + # List merge requests # # Parameters: @@ -60,13 +77,7 @@ module Gitlab merge_request.reload_code present merge_request, with: Entities::MergeRequest else - if merge_request.errors[:target_branch].any? - error!(merge_request.errors[:target_branch], 400) - elsif merge_request.errors[:source_branch].any? - error!(merge_request.errors[:source_branch], 400) - elsif merge_request.errors[:base].any? - error!(merge_request.errors[:base], 422) - end + handle_merge_request_error(merge_request.errors) not_found! end end @@ -95,13 +106,7 @@ module Gitlab merge_request.mark_as_unchecked present merge_request, with: Entities::MergeRequest else - if merge_request.errors[:target_branch].any? - error!(merge_request.errors[:target_branch], 400) - elsif merge_request.errors[:source_branch].any? - error!(merge_request.errors[:source_branch], 400) - elsif merge_request.errors[:base].any? - error!(merge_request.errors[:base], 422) - end + handle_merge_request_error(merge_request.errors) not_found! end end From f978a71f41d5546be2c0c6b33052979c06912bd1 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 5 Feb 2013 18:37:44 +0100 Subject: [PATCH 10/49] Creating MR comment without a note returns status code 400 (Bad request) Creating a comment to an existing merge request via API without providing a note returns a status code 400 now, suggesting a bad request. The reason for this is the resource itself (MR) exists but the required property is not set. --- lib/api/merge_requests.rb | 3 +++ spec/requests/api/merge_requests_spec.rb | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index ec63b352..a0ca3026 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -128,6 +128,9 @@ module Gitlab if note.save present note, with: Entities::MRNote else + if note.errors[:note].any? + error!(note.errors[:note], 400) + end not_found! end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index bf87ecbd..531b56b8 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -87,6 +87,11 @@ describe Gitlab::API do response.status.should == 201 json_response['note'].should == 'My comment' end + + it "should return 400 if note is missing" do + post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user) + response.status.should == 400 + end end end From 41e93bbfe23b3791d1b440dd3961d4fadfbb8461 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 14:59:47 +0100 Subject: [PATCH 11/49] Test added to check creation of note to a non-existent MR via API --- spec/requests/api/merge_requests_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 531b56b8..4e7a84df 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -92,6 +92,11 @@ describe Gitlab::API do post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user) response.status.should == 400 end + + it "should return 404 if note is attached to non existent merge request" do + post api("/projects/#{project.id}/merge_request/111/comments", user), note: "My comment" + response.status.should == 404 + end end end From 5be0265fe7e82a127e9fd2805e81e4e40f5e3c5f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 15:03:05 +0100 Subject: [PATCH 12/49] Status code 400 returned if title not given in a milestone (via API) If a milestone is created via API but no title given then status code 400 (Bad request) is returned instead of 404. A small helper method handles the errors collection of a milestone. --- lib/api/milestones.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 6aca9d01..1f7d0876 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -4,6 +4,20 @@ module Gitlab before { authenticate! } resource :projects do + + helpers do + # If an error occurs this helper method handles error codes for a given milestone + # + # Parameters: + # milestone_errors (required) - The erros collection of a milestone + # + def handle_milestone_errors(milestone_errors) + if milestone_errors[:title].any? + error!(milestone_errors[:title], 400) + end + end + end + # Get a list of project milestones # # Parameters: @@ -47,6 +61,7 @@ module Gitlab if @milestone.save present @milestone, with: Entities::Milestone else + handle_milestone_errors(@milestone.errors) not_found! end end @@ -70,6 +85,7 @@ module Gitlab if @milestone.update_attributes attrs present @milestone, with: Entities::Milestone else + handle_milestone_errors(@milestone.errors) not_found! end end From b9d40d2524a78013737be16b4cd0976ded843a1b Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 15:05:56 +0100 Subject: [PATCH 13/49] Tests added to check status codes when handling milestone via API A few more tests added to check status code when creating or updating milestones. --- spec/requests/api/milestones_spec.rb | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index 80696671..3cab6355 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -24,6 +24,11 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == milestone.title end + + it "should return a 404 error if milestone id not found" do + get api("/projects/#{project.id}/milestones/1234", user) + response.status.should == 404 + end end describe "POST /projects/:id/milestones" do @@ -34,6 +39,19 @@ describe Gitlab::API do json_response['title'].should == 'new milestone' json_response['description'].should be_nil end + + it "should create a new project milestone with description and due date" do + post api("/projects/#{project.id}/milestones", user), + title: 'new milestone', description: 'release', due_date: '2013-03-02' + response.status.should == 201 + json_response['description'].should == 'release' + json_response['due_date'].should == '2013-03-02' + end + + it "should return a 400 error if title is missing" do + post api("/projects/#{project.id}/milestones", user) + response.status.should == 400 + end end describe "PUT /projects/:id/milestones/:milestone_id" do @@ -43,5 +61,11 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == 'updated title' end + + it "should return a 404 error if milestone is not found" do + put api("/projects/#{project.id}/milestones/1234", user), + title: 'updated title' + response.status.should == 404 + end end end From bb24275f8d0e726aec347c8be7f199346e90793d Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 16:34:06 +0100 Subject: [PATCH 14/49] Status code 400 is returned if body is missing on note creation. If a note is created with a POST request via API (`/projects/:id/notes`) status code 400 is returned instead of 404. The resource itself exists but the request is incomplete. Specs added to check different status codes when accessing, creating and updating notes. --- lib/api/notes.rb | 2 ++ spec/requests/api/notes_spec.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 4613db54..75ea238f 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -43,6 +43,8 @@ module Gitlab if @note.save present @note, with: Entities::Note else + # :note is exposed as :body, but :note is set on error + error!(@note.errors[:note], 400) if @note.errors[:note].any? not_found! end end diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index ae4fc111..a4abbd93 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -36,6 +36,11 @@ describe Gitlab::API do response.status.should == 200 json_response['body'].should == wall_note.note end + + it "should return a 404 error if note not found" do + get api("/projects/#{project.id}/notes/123", user) + response.status.should == 404 + end end describe "POST /projects/:id/notes" do @@ -44,6 +49,11 @@ describe Gitlab::API do response.status.should == 201 json_response['body'].should == 'hi!' end + + it "should return a 400 error if body is missing" do + post api("/projects/#{project.id}/notes", user) + response.status.should == 400 + end end describe "GET /projects/:id/noteable/:noteable_id/notes" do @@ -54,6 +64,11 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['body'].should == issue_note.note end + + it "should return a 404 error when issue id not found" do + get api("/projects/#{project.id}/issues/123/notes", user) + response.status.should == 404 + end end context "when noteable is a Snippet" do @@ -63,6 +78,11 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['body'].should == snippet_note.note end + + it "should return a 404 error when snippet id not found" do + get api("/projects/#{project.id}/snippets/42/notes", user) + response.status.should == 404 + end end end @@ -73,6 +93,11 @@ describe Gitlab::API do response.status.should == 200 json_response['body'].should == issue_note.note end + + it "should return a 404 error if issue note not found" do + get api("/projects/#{project.id}/issues/#{issue.id}/notes/123", user) + response.status.should == 404 + end end context "when noteable is a Snippet" do @@ -81,6 +106,11 @@ describe Gitlab::API do response.status.should == 200 json_response['body'].should == snippet_note.note end + + it "should return a 404 error if snippet note not found" do + get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/123", user) + response.status.should == 404 + end end end From a534c9b72d54729122a9ccfe4f43ce5bdaa9bed2 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 16:41:36 +0100 Subject: [PATCH 15/49] A few fixes in documentation to notes, updates infos on status codes A few fixes in the notes URI pattern (`notes` instead of `:notes`), also updated the information to status codes. If `body` attribute is missing from a POST request a status code 400 (Bad request) is returned. This reflects the code changes from the previous commit. --- doc/api/notes.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/api/notes.md b/doc/api/notes.md index bb33efb8..30480d56 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -76,7 +76,7 @@ Parameters: Get an issue note. ``` -GET /projects/:id/issues/:issue_id/:notes/:note_id +GET /projects/:id/issues/:issue_id/notes/:note_id ``` Parameters: @@ -90,7 +90,7 @@ Parameters: Get a snippet note. ``` -GET /projects/:id/issues/:snippet_id/:notes/:note_id +GET /projects/:id/issues/:snippet_id/notes/:note_id ``` Parameters: @@ -114,7 +114,7 @@ Parameters: + `id` (required) - The ID of a project + `body` (required) - The content of a note -Will return created note with status `201 Created` on success, or `404 Not found` on fail. +Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. ### New issue note @@ -131,7 +131,7 @@ Parameters: + `issue_id` (required) - The ID of an issue + `body` (required) - The content of a note -Will return created note with status `201 Created` on success, or `404 Not found` on fail. +Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. ### New snippet note @@ -147,4 +147,4 @@ Parameters: + `snippet_id` (required) - The ID of an snippet + `body` (required) - The content of a note -Will return created note with status `201 Created` on success, or `404 Not found` on fail. +Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. From 5d8a99f10429168e6471fdd1843f5045a10a84b3 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 16:45:38 +0100 Subject: [PATCH 16/49] Test to check a user must be part of the team to see project. A user must be part of the team to see a protected project. A test is given to check that a 404 error is returned if the user can not see the project. --- spec/requests/api/projects_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 8351b4bf..b9f42acc 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -89,6 +89,12 @@ describe Gitlab::API do response.status.should == 404 json_response['message'].should == '404 Not Found' end + + it "should return a 404 error if user is not a member" do + other_user = create(:user) + get api("/projects/#{project.id}", other_user) + response.status.should == 404 + end end describe "GET /projects/:id/repository/branches" do From 818caf0b5d1fc4f0cb2889ca5bd9e2d0d7fd8ac8 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 8 Feb 2013 14:33:29 +0100 Subject: [PATCH 17/49] API: refined status code handling when adding or updating a project member When a user is added to a project that is already a member of, a status code 201 is now returned to signal an idempotent operation. If something fails then instead of returning error code 404 different more specific error codes are returned. Status code 400 (Bad request) is returned when a required attribute, e.g. `access_level` is not given or 422 if there is a semantic error, e.g. should the `access_level` have an unsupported value. Specs are added to check these status codes. --- lib/api/projects.rb | 35 +++++++++++++++++------- spec/requests/api/projects_spec.rb | 43 ++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 47ab4e1a..e6df6b4e 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -89,15 +89,26 @@ module Gitlab # POST /projects/:id/members post ":id/members" do authorize! :admin_project, user_project - users_project = user_project.users_projects.new( - user_id: params[:user_id], - project_access: params[:access_level] - ) - if users_project.save - @member = users_project.user + error!("User id not given", 400) if !params.has_key? :user_id + error!("Access level not given", 400) if !params.has_key? :access_level + + # either the user is already a team member or a new one + team_member = user_project.team_member_by_id(params[:user_id]) + if team_member.nil? + team_member = user_project.users_projects.new( + user_id: params[:user_id], + project_access: params[:access_level] + ) + end + + if team_member.save + @member = team_member.user present @member, with: Entities::ProjectMember, project: user_project else + if team_member.errors[:project_access].any? + error!(team_member.errors[:project_access], 422) + end not_found! end end @@ -112,12 +123,18 @@ module Gitlab # PUT /projects/:id/members/:user_id put ":id/members/:user_id" do authorize! :admin_project, user_project - users_project = user_project.users_projects.find_by_user_id params[:user_id] - if users_project.update_attributes(project_access: params[:access_level]) - @member = users_project.user + team_member = user_project.users_projects.find_by_user_id(params[:user_id]) + error!("Access level not given", 400) if !params.has_key? :access_level + error!("User can not be found", 404) if team_member.nil? + + if team_member.update_attributes(project_access: params[:access_level]) + @member = team_member.user present @member, with: Entities::ProjectMember, project: user_project else + if team_member.errors[:project_access].any? + error!(team_member.errors[:project_access], 422) + end not_found! end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 2682629e..91632407 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -177,6 +177,34 @@ describe Gitlab::API do json_response['email'].should == user2.email json_response['access_level'].should == UsersProject::DEVELOPER end + + it "should return a 201 status if user is already project member" do + post api("/projects/#{project.id}/members", user), user_id: user2.id, + access_level: UsersProject::DEVELOPER + expect { + post api("/projects/#{project.id}/members", user), user_id: user2.id, + access_level: UsersProject::DEVELOPER + }.not_to change { UsersProject.count }.by(1) + + response.status.should == 201 + json_response['email'].should == user2.email + json_response['access_level'].should == UsersProject::DEVELOPER + end + + it "should return a 400 error when user id is not given" do + post api("/projects/#{project.id}/members", user), access_level: UsersProject::MASTER + response.status.should == 400 + end + + it "should return a 400 error when access level is not given" do + post api("/projects/#{project.id}/members", user), user_id: user2.id + response.status.should == 400 + end + + it "should return a 422 error when access level is not known" do + post api("/projects/#{project.id}/members", user), user_id: user2.id, access_level: 1234 + response.status.should == 422 + end end describe "PUT /projects/:id/members/:user_id" do @@ -186,6 +214,21 @@ describe Gitlab::API do json_response['email'].should == user3.email json_response['access_level'].should == UsersProject::MASTER end + + it "should return a 404 error if user_id is not found" do + put api("/projects/#{project.id}/members/1234", user), access_level: UsersProject::MASTER + response.status.should == 404 + end + + it "should return a 400 error when access level is not given" do + put api("/projects/#{project.id}/members/#{user3.id}", user) + response.status.should == 400 + end + + it "should return a 422 error when access level is not known" do + put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: 123 + response.status.should == 422 + end end describe "DELETE /projects/:id/members/:user_id" do From 9544f9038981b881b539419be72276b2b2fd079f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 8 Feb 2013 16:33:15 +0100 Subject: [PATCH 18/49] Adding a project hook returns status code 400 if url is not given When adding a project hook a url must be specified or a 400 error code is returned * Specs added to check status code on handling project hooks * refactored code, extracted a method --- lib/api/projects.rb | 24 +++++++++++++++--------- spec/requests/api/projects_spec.rb | 29 ++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index e6df6b4e..f1e0f32e 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -4,6 +4,15 @@ module Gitlab before { authenticate! } resource :projects do + helpers do + def handle_project_member_errors(errors) + if errors[:project_access].any? + error!(errors[:project_access], 422) + end + not_found! + end + end + # Get a projects list for authenticated user # # Example Request: @@ -36,6 +45,7 @@ module Gitlab # Example Request # POST /projects post do + error!("Name is required", 400) if !params.has_key? :name attrs = attributes_for_keys [:name, :description, :default_branch, @@ -43,6 +53,7 @@ module Gitlab :wall_enabled, :merge_requests_enabled, :wiki_enabled] + @project = ::Projects::CreateContext.new(current_user, attrs).execute if @project.saved? present @project, with: Entities::Project @@ -106,10 +117,7 @@ module Gitlab @member = team_member.user present @member, with: Entities::ProjectMember, project: user_project else - if team_member.errors[:project_access].any? - error!(team_member.errors[:project_access], 422) - end - not_found! + handle_project_member_errors team_member.errors end end @@ -132,10 +140,7 @@ module Gitlab @member = team_member.user present @member, with: Entities::ProjectMember, project: user_project else - if team_member.errors[:project_access].any? - error!(team_member.errors[:project_access], 422) - end - not_found! + handle_project_member_errors team_member.errors end end @@ -210,8 +215,9 @@ module Gitlab @hook = user_project.hooks.find(params[:hook_id]) authorize! :admin_project, user_project - attrs = attributes_for_keys [:url] + error!("Url not given", 400) if !params.has_key? :url + attrs = attributes_for_keys [:url] if @hook.update_attributes attrs present @hook, with: Entities::Hook else diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 91632407..11c3d012 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -46,9 +46,9 @@ describe Gitlab::API do response.status.should == 201 end - it "should respond with 404 on failure" do + it "should respond with 400 if name is not given" do post api("/projects", user) - response.status.should == 404 + response.status.should == 400 end it "should assign attributes to project" do @@ -237,6 +237,13 @@ describe Gitlab::API do delete api("/projects/#{project.id}/members/#{user3.id}", user) }.to change { UsersProject.count }.by(-1) end + + it "should return 200 if team member is not part of a project" do + delete api("/projects/#{project.id}/members/#{user3.id}", user) + expect { + delete api("/projects/#{project.id}/members/#{user3.id}", user) + }.to_not change { UsersProject.count }.by(1) + end end describe "DELETE /projects/:id/members/:user_id" do @@ -268,6 +275,11 @@ describe Gitlab::API do response.status.should == 200 json_response['url'].should == hook.url end + + it "should return a 404 error if hook id is not available" do + get api("/projects/#{project.id}/hooks/1234", user) + response.status.should == 404 + end end describe "POST /projects/:id/hooks" do @@ -276,6 +288,7 @@ describe Gitlab::API do post api("/projects/#{project.id}/hooks", user), "url" => "http://example.com" }.to change {project.hooks.count}.by(1) + response.status.should == 200 end end @@ -286,8 +299,17 @@ describe Gitlab::API do response.status.should == 200 json_response['url'].should == 'http://example.org' end - end + it "should return 404 error if hook id is not found" do + put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org' + response.status.should == 404 + end + + it "should return 400 error if url is not given" do + put api("/projects/#{project.id}/hooks/#{hook.id}", user) + response.status.should == 400 + end + end describe "DELETE /projects/:id/hooks" do it "should delete hook from project" do @@ -295,6 +317,7 @@ describe Gitlab::API do delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id }.to change {project.hooks.count}.by(-1) + response.status.should == 200 end end From 56b3223945637d25394b001c880626f9a4a5b9e0 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 8 Feb 2013 18:19:59 +0100 Subject: [PATCH 19/49] Fixes test that checks status code of hook creation --- spec/requests/api/projects_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 11c3d012..6f53b38c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -288,7 +288,7 @@ describe Gitlab::API do post api("/projects/#{project.id}/hooks", user), "url" => "http://example.com" }.to change {project.hooks.count}.by(1) - response.status.should == 200 + response.status.should == 201 end end From 7cc4339f71be5a71e1d8a95c4524c4671e9d8a24 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 12 Feb 2013 17:44:42 +0100 Subject: [PATCH 20/49] API: changed status codes for project hooks functions Different status codes in the API lib are returned on hook creation, update or deletion. If a required parameter is not given (e.g. `url` in `/projects/:id/hooks/:hook_id`) status code 400 (Bad request) is returned. On hook deletion a 200 status code is returned, regardless if the hook is present or not. This makes the DELETE function an idempotent operation. Appropriate tests are added to check these status codes. --- lib/api/projects.rb | 16 ++++++++++++---- spec/requests/api/projects_spec.rb | 24 ++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index f1e0f32e..293353ab 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -195,11 +195,14 @@ module Gitlab # POST /projects/:id/hooks post ":id/hooks" do authorize! :admin_project, user_project + + error!("Url not given", 400) unless params.has_key? :url + @hook = user_project.hooks.new({"url" => params[:url]}) if @hook.save present @hook, with: Entities::Hook else - error!({'message' => '404 Not found'}, 404) + not_found! end end @@ -215,7 +218,7 @@ module Gitlab @hook = user_project.hooks.find(params[:hook_id]) authorize! :admin_project, user_project - error!("Url not given", 400) if !params.has_key? :url + error!("Url not given", 400) unless params.has_key? :url attrs = attributes_for_keys [:url] if @hook.update_attributes attrs @@ -234,8 +237,13 @@ module Gitlab # DELETE /projects/:id/hooks delete ":id/hooks" do authorize! :admin_project, user_project - @hook = user_project.hooks.find(params[:hook_id]) - @hook.destroy + error!("Hook id not given", 400) unless params.has_key? :hook_id + + begin + @hook = ProjectHook.find(params[:hook_id]) + @hook.destroy + rescue + end end # Get a project repository branches diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 6f53b38c..18fd1cae 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -6,8 +6,8 @@ describe Gitlab::API do let(:user) { create(:user) } let(:user2) { create(:user) } let(:user3) { create(:user) } - let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } let!(:project) { create(:project, namespace: user.namespace ) } + let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } @@ -290,6 +290,11 @@ describe Gitlab::API do }.to change {project.hooks.count}.by(1) response.status.should == 201 end + + it "should return a 400 error if url not given" do + post api("/projects/#{project.id}/hooks", user) + response.status.should == 400 + end end describe "PUT /projects/:id/hooks/:hook_id" do @@ -300,7 +305,7 @@ describe Gitlab::API do json_response['url'].should == 'http://example.org' end - it "should return 404 error if hook id is not found" do + it "should return 404 error if hook id not found" do put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org' response.status.should == 404 end @@ -319,6 +324,21 @@ describe Gitlab::API do }.to change {project.hooks.count}.by(-1) response.status.should == 200 end + + it "should return success when deleting hook" do + delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id + response.status.should == 200 + end + + it "should return success when deleting non existent hook" do + delete api("/projects/#{project.id}/hooks", user), hook_id: 42 + response.status.should == 200 + end + + it "should return a 400 error if hook id not given" do + delete api("/projects/#{project.id}/hooks", user) + response.status.should == 400 + end end describe "GET /projects/:id/repository/tags" do From 82bd0904ffb34e16ac66fb83a9ce79a5845ce78b Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 10:25:13 +0100 Subject: [PATCH 21/49] API: test checks a 404 error is returned if snippet id not found --- spec/requests/api/projects_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 18fd1cae..1e77baf7 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -386,6 +386,11 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == snippet.title end + + it "should return a 404 error if snippet id not found" do + get api("/projects/#{project.id}/snippets/1234", user) + response.status.should == 404 + end end describe "POST /projects/:id/snippets" do From ae40e855efc393d752f290ed8eda67961874acf5 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 10:29:42 +0100 Subject: [PATCH 22/49] API: test checks a 400 code is returned if snippet title not given --- spec/requests/api/projects_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 1e77baf7..9881ece3 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -400,6 +400,12 @@ describe Gitlab::API do response.status.should == 201 json_response['title'].should == 'api test' end + + it "should return a 400 error if title is not given" do + post api("/projects/#{project.id}/snippets", user), + file_name: 'sample.rb', code: 'test' + response.status.should == 400 + end end describe "PUT /projects/:id/snippets/:shippet_id" do From fd01f3aacda1e7e1966489e7d9a31f89745cd509 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 12:09:16 +0100 Subject: [PATCH 23/49] API: fixes a few return codes for project snippets When using project snippets via API the functions now provide status codes for different situations other then only returning 404 error. If required parameters are missing, e.g. `title` when creating a project snippet a 400 (Bad request) error is returned. The snippet delete function now is idempotent and returns a 200 (Ok) regardless if the snippet with the given id is available or not. Changing return codes of these functions has the advantage that the 404 error is used only for resources, which are not available. Tests added to check these status codes when handling project snippets. --- lib/api/projects.rb | 14 ++++++++++---- spec/requests/api/projects_spec.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index f8c9701e..02f10b60 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -368,6 +368,10 @@ module Gitlab post ":id/snippets" do authorize! :write_snippet, user_project + error!("Title not given", 400) if !params[:title].present? + error!("Filename not given", 400) if !params[:file_name].present? + error!("Code not given", 400) if !params[:code].present? + attrs = attributes_for_keys [:title, :file_name] attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? attrs[:content] = params[:code] if params[:code].present? @@ -415,10 +419,12 @@ module Gitlab # Example Request: # DELETE /projects/:id/snippets/:snippet_id delete ":id/snippets/:snippet_id" do - @snippet = user_project.snippets.find(params[:snippet_id]) - authorize! :modify_snippet, @snippet - - @snippet.destroy + begin + @snippet = user_project.snippets.find(params[:snippet_id]) + authorize! :modify_snippet, user_project + @snippet.destroy + rescue + end end # Get a raw project snippet diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 7a3677d1..a04c2318 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -411,6 +411,18 @@ describe Gitlab::API do file_name: 'sample.rb', code: 'test' response.status.should == 400 end + + it "should return a 400 error if file_name not given" do + post api("/projects/#{project.id}/snippets", user), + title: 'api test', code: 'test' + response.status.should == 400 + end + + it "should return a 400 error if code not given" do + post api("/projects/#{project.id}/snippets", user), + title: 'api test', file_name: 'sample.rb' + response.status.should == 400 + end end describe "PUT /projects/:id/snippets/:shippet_id" do @@ -421,6 +433,13 @@ describe Gitlab::API do json_response['title'].should == 'example' snippet.reload.content.should == 'updated code' end + + it "should update an existing project snippet with new title" do + put api("/projects/#{project.id}/snippets/#{snippet.id}", user), + title: 'other api test' + response.status.should == 200 + json_response['title'].should == 'other api test' + end end describe "DELETE /projects/:id/snippets/:snippet_id" do @@ -428,6 +447,12 @@ describe Gitlab::API do expect { delete api("/projects/#{project.id}/snippets/#{snippet.id}", user) }.to change { Snippet.count }.by(-1) + response.status.should == 200 + end + + it "should return success when deleting unknown snippet id" do + delete api("/projects/#{project.id}/snippets/1234", user) + response.status.should == 200 end end @@ -436,6 +461,11 @@ describe Gitlab::API do get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user) response.status.should == 200 end + + it "should return a 404 error if raw project snippet not found" do + get api("/projects/#{project.id}/snippets/5555/raw", user) + response.status.should == 404 + end end describe "GET /projects/:id/:sha/blob" do From 54ab9bb6df3a2cd9f9384aebae07e0b18acee10b Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 14:47:59 +0100 Subject: [PATCH 24/49] API: return status code 400 if filepath of raw file blob not given --- lib/api/projects.rb | 2 ++ spec/requests/api/projects_spec.rb | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 02f10b60..24761cd5 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -451,6 +451,8 @@ module Gitlab get ":id/repository/commits/:sha/blob" do authorize! :download_code, user_project + error!("Filepath must be specified", 400) if !params.has_key? :filepath + ref = params[:sha] commit = user_project.repository.commit ref diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index a04c2318..de1b1b09 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -468,7 +468,7 @@ describe Gitlab::API do end end - describe "GET /projects/:id/:sha/blob" do + describe "GET /projects/:id/repository/commits/:sha/blob" do it "should get the raw file contents" do get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.md", user) response.status.should == 200 @@ -483,5 +483,10 @@ describe Gitlab::API do get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.invalid", user) response.status.should == 404 end + + it "should return a 400 error if filepath is missing" do + get api("/projects/#{project.id}/repository/commits/master/blob", user) + response.status.should == 400 + end end end From 6fc3263e15b71830e6f1b2a66891da5f4c055137 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 15:48:52 +0100 Subject: [PATCH 25/49] API: extracted helper method to provide 400 bad request error with description Extracted a method for 400 error (Bad request) and adjusted code accordingly. The name of the missing attribute is used to show which one was missing from the request. It is used to give an appropriate message in the json response. --- lib/api/helpers.rb | 6 ++++++ lib/api/merge_requests.rb | 6 +++--- lib/api/milestones.rb | 2 +- lib/api/notes.rb | 2 +- lib/api/projects.rb | 24 ++++++++++++------------ spec/requests/api/merge_requests_spec.rb | 5 +++++ 6 files changed, 28 insertions(+), 17 deletions(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 6bd8111c..becb3bce 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -55,6 +55,12 @@ module Gitlab render_api_error!('403 Forbidden', 403) end + def bad_request!(attribute) + message = ["400 (Bad request)"] + message << "\"" + attribute.to_s + "\" not given" + render_api_error!(message.join(' '), 400) + end + def not_found!(resource = nil) message = ["404"] message << resource if resource diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index a0ca3026..0c18ece3 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -13,9 +13,9 @@ module Gitlab # def handle_merge_request_error(merge_request_errors) if merge_request_errors[:target_branch].any? - error!(merge_request_errors[:target_branch], 400) + bad_request!(:target_branch) elsif merge_request_errors[:source_branch].any? - error!(merge_request_errors[:source_branch], 400) + bad_request!(:source_branch) elsif merge_request_errors[:base].any? error!(merge_request_errors[:base], 422) end @@ -129,7 +129,7 @@ module Gitlab present note, with: Entities::MRNote else if note.errors[:note].any? - error!(note.errors[:note], 400) + bad_request!(:note) end not_found! end diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 1f7d0876..cdb0e146 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -13,7 +13,7 @@ module Gitlab # def handle_milestone_errors(milestone_errors) if milestone_errors[:title].any? - error!(milestone_errors[:title], 400) + bad_request!(:title) end end end diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 47dead9d..56de6e09 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -44,7 +44,7 @@ module Gitlab present @note, with: Entities::Note else # :note is exposed as :body, but :note is set on error - error!(@note.errors[:note], 400) if @note.errors[:note].any? + bad_request!(:note) if @note.errors[:note].any? not_found! end end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 24761cd5..ecd3401f 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -45,7 +45,7 @@ module Gitlab # Example Request # POST /projects post do - error!("Name is required", 400) if !params.has_key? :name + bad_request!(:name) if !params.has_key? :name attrs = attributes_for_keys [:name, :description, :default_branch, @@ -101,8 +101,8 @@ module Gitlab post ":id/members" do authorize! :admin_project, user_project - error!("User id not given", 400) if !params.has_key? :user_id - error!("Access level not given", 400) if !params.has_key? :access_level + bad_request!(:user_id) if !params.has_key? :user_id + bad_request!(:access_level) if !params.has_key? :access_level # either the user is already a team member or a new one team_member = user_project.team_member_by_id(params[:user_id]) @@ -133,8 +133,8 @@ module Gitlab authorize! :admin_project, user_project team_member = user_project.users_projects.find_by_user_id(params[:user_id]) - error!("Access level not given", 400) if !params.has_key? :access_level - error!("User can not be found", 404) if team_member.nil? + bad_request!(:access_level) if !params.has_key? :access_level + not_found!("User can not be found") if team_member.nil? if team_member.update_attributes(project_access: params[:access_level]) @member = team_member.user @@ -196,7 +196,7 @@ module Gitlab post ":id/hooks" do authorize! :admin_project, user_project - error!("Url not given", 400) unless params.has_key? :url + bad_request!(:url) unless params.has_key? :url @hook = user_project.hooks.new({"url" => params[:url]}) if @hook.save @@ -218,7 +218,7 @@ module Gitlab @hook = user_project.hooks.find(params[:hook_id]) authorize! :admin_project, user_project - error!("Url not given", 400) unless params.has_key? :url + bad_request!(:url) unless params.has_key? :url attrs = attributes_for_keys [:url] if @hook.update_attributes attrs @@ -237,7 +237,7 @@ module Gitlab # DELETE /projects/:id/hooks delete ":id/hooks" do authorize! :admin_project, user_project - error!("Hook id not given", 400) unless params.has_key? :hook_id + bad_request!(:hook_id) unless params.has_key? :hook_id begin @hook = ProjectHook.find(params[:hook_id]) @@ -368,9 +368,9 @@ module Gitlab post ":id/snippets" do authorize! :write_snippet, user_project - error!("Title not given", 400) if !params[:title].present? - error!("Filename not given", 400) if !params[:file_name].present? - error!("Code not given", 400) if !params[:code].present? + bad_request!(:title) if !params[:title].present? + bad_request!(:file_name) if !params[:file_name].present? + bad_request!(:code) if !params[:code].present? attrs = attributes_for_keys [:title, :file_name] attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? @@ -451,7 +451,7 @@ module Gitlab get ":id/repository/commits/:sha/blob" do authorize! :download_code, user_project - error!("Filepath must be specified", 400) if !params.has_key? :filepath + bad_request!(:filepath) if !params.has_key? :filepath ref = params[:sha] diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 4e7a84df..431aae7c 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -32,6 +32,11 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == merge_request.title end + + it "should return a 404 error if merge_request_id not found" do + get api("/projects/#{project.id}/merge_request/999", user) + response.status.should == 404 + end end describe "POST /projects/:id/merge_requests" do From 6df02adc7a5cb7badf748be783f9a552cf19aeee Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 14 Feb 2013 15:51:56 +0100 Subject: [PATCH 26/49] API: status code 403 returned if new project would exceed limit When the project limit is reached the user is not allowed to create new ones. Instead of error code 404 the status code 403 (Forbidden) is returned with error message via API. --- app/models/project.rb | 2 +- lib/api/projects.rb | 3 +++ spec/requests/api/projects_spec.rb | 13 +++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index acc1b8d2..ce429bc3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -155,7 +155,7 @@ class Project < ActiveRecord::Base def check_limit unless creator.can_create_project? - errors[:base] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it") + errors[:limit_reached] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it") end rescue errors[:base] << ("Can't check your ability to create project") diff --git a/lib/api/projects.rb b/lib/api/projects.rb index ecd3401f..87653f04 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -58,6 +58,9 @@ module Gitlab if @project.saved? present @project, with: Entities::Project else + if @project.errors[:limit_reached].present? + error!(@project.errors[:limit_reached], 403) + end not_found! end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index de1b1b09..b6353078 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -41,6 +41,11 @@ describe Gitlab::API do expect { post api("/projects", user) }.to_not change {Project.count} end + it "should return a 400 error if name not given" do + post api("/projects", user) + response.status.should == 400 + end + it "should respond with 201 on success" do post api("/projects", user), name: 'foo' response.status.should == 201 @@ -51,6 +56,14 @@ describe Gitlab::API do response.status.should == 400 end + it "should return a 403 error if project limit reached" do + (1..user.projects_limit).each do |p| + post api("/projects", user), name: "foo#{p}" + end + post api("/projects", user), name: 'bar' + response.status.should == 403 + end + it "should assign attributes to project" do project = attributes_for(:project, { description: Faker::Lorem.sentence, From c305eb31aa1cf1aec24b907e0db1d7b2084400dc Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 14 Feb 2013 16:55:33 +0100 Subject: [PATCH 27/49] API: tests that check status codes for project branches and hooks Status code 422 (Unprocessable Entity) returned if invalid url is given when creating or updating a project hook. --- lib/api/projects.rb | 14 +++++++--- spec/requests/api/projects_spec.rb | 43 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 87653f04..cf3e8257 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -156,9 +156,9 @@ module Gitlab # DELETE /projects/:id/members/:user_id delete ":id/members/:user_id" do authorize! :admin_project, user_project - users_project = user_project.users_projects.find_by_user_id params[:user_id] - unless users_project.nil? - users_project.destroy + team_member = user_project.users_projects.find_by_user_id(params[:user_id]) + unless team_member.nil? + team_member.destroy else {:message => "Access revoked", :id => params[:user_id].to_i} end @@ -205,6 +205,9 @@ module Gitlab if @hook.save present @hook, with: Entities::Hook else + if @hook.errors[:url].present? + error!("Invalid url given", 422) + end not_found! end end @@ -227,6 +230,9 @@ module Gitlab if @hook.update_attributes attrs present @hook, with: Entities::Hook else + if @hook.errors[:url].present? + error!("Invalid url given", 422) + end not_found! end end @@ -281,6 +287,7 @@ module Gitlab # PUT /projects/:id/repository/branches/:branch/protect put ":id/repository/branches/:branch/protect" do @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + not_found! unless @branch protected = user_project.protected_branches.find_by_name(@branch.name) unless protected @@ -299,6 +306,7 @@ module Gitlab # PUT /projects/:id/repository/branches/:branch/unprotect put ":id/repository/branches/:branch/unprotect" do @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + not_found! unless @branch protected = user_project.protected_branches.find_by_name(@branch.name) if protected diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index b6353078..96f58dde 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -144,6 +144,17 @@ describe Gitlab::API do json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1' json_response['protected'].should == true end + + it "should return a 404 error if branch not found" do + put api("/projects/#{project.id}/repository/branches/unknown/protect", user) + response.status.should == 404 + end + + it "should return success when protect branch again" do + put api("/projects/#{project.id}/repository/branches/new_design/protect", user) + put api("/projects/#{project.id}/repository/branches/new_design/protect", user) + response.status.should == 200 + end end describe "PUT /projects/:id/repository/branches/:branch/unprotect" do @@ -155,6 +166,17 @@ describe Gitlab::API do json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1' json_response['protected'].should == false end + + it "should return success when unprotect branch" do + put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user) + response.status.should == 404 + end + + it "should return success when unprotect branch again" do + put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user) + put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user) + response.status.should == 200 + end end describe "GET /projects/:id/members" do @@ -182,6 +204,11 @@ describe Gitlab::API do json_response['email'].should == user.email json_response['access_level'].should == UsersProject::MASTER end + + it "should return a 404 error if user id not found" do + get api("/projects/#{project.id}/members/1234", user) + response.status.should == 404 + end end describe "POST /projects/:id/members" do @@ -262,6 +289,12 @@ describe Gitlab::API do delete api("/projects/#{project.id}/members/#{user3.id}", user) }.to_not change { UsersProject.count }.by(1) end + + it "should return 200 if team member already removed" do + delete api("/projects/#{project.id}/members/#{user3.id}", user) + delete api("/projects/#{project.id}/members/#{user3.id}", user) + response.status.should == 200 + end end describe "DELETE /projects/:id/members/:user_id" do @@ -313,6 +346,11 @@ describe Gitlab::API do post api("/projects/#{project.id}/hooks", user) response.status.should == 400 end + + it "should return a 422 error if url not valid" do + post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com" + response.status.should == 422 + end end describe "PUT /projects/:id/hooks/:hook_id" do @@ -332,6 +370,11 @@ describe Gitlab::API do put api("/projects/#{project.id}/hooks/#{hook.id}", user) response.status.should == 400 end + + it "should return a 422 error if url is not valid" do + put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com' + response.status.should == 422 + end end describe "DELETE /projects/:id/hooks" do From 12a1f73b6126a3495c338287ad3ada0267657b4a Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 14 Feb 2013 20:43:48 +0100 Subject: [PATCH 28/49] API projects documentation grouped into sections & updated with status codes The API documentation for projects now is structured into major sections that describe the different aspects when dealing with projects, e.g. hooks, branches, team members etc. All described methods now contain a list of possible status codes the method can return. A few methods have extra sample JSON responses and a description if a method is idempotent. Idempotent methods can be called multiple times while returning the same status code. --- doc/api/projects.md | 151 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 34 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 03731427..a36890a4 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1,4 +1,6 @@ -## List projects +## Projects + +### List projects Get a list of projects owned by the authenticated user. @@ -55,7 +57,8 @@ GET /projects ] ``` -## Single project + +### Get single project Get a specific project, identified by project ID, which is owned by the authentication user. @@ -92,9 +95,15 @@ Parameters: } ``` -## Create project +Return Values: -Create new project owned by user ++ `200 Ok` if the project with given ID is found and the JSON response ++ `404 Not Found` if no project with ID found + + +### Create project + +Creates new project owned by user. ``` POST /projects @@ -110,10 +119,15 @@ Parameters: + `merge_requests_enabled` (optional) - enabled by default + `wiki_enabled` (optional) - enabled by default -Will return created project with status `201 Created` on success, or `404 Not -found` on fail. +Return values: -## List project team members ++ `201 Created` on success with the project data (see example at `GET /projects/:id`) ++ `400 Bad Request` if the required attribute name is not given ++ `403 Forbidden` if the user is not allowed to create a project, e.g. reached the project limit already ++ `404 Not Found` if something else fails + + +### List project members Get a list of project team members. @@ -126,7 +140,15 @@ Parameters: + `id` (required) - The ID of a project + `query` - Query string -## Get project team member +Return Values: + ++ `200 Ok` on success and a list of found team members ++ `404 Not Found` if project with ID not found + + +## Team members + +### Get project team member Get a project team member. @@ -141,7 +163,6 @@ Parameters: ```json { - "id": 1, "username": "john_smith", "email": "john@example.com", @@ -152,9 +173,17 @@ Parameters: } ``` -## Add project team member +Return Values: -Add a user to a project team. ++ `200 Ok` on success and the team member, see example ++ `404 Not Found` if either the project or the team member could not be found + + +### Add project team member + +Adds a user to a project team. This is an idempotent method and can be called multiple times +with the same parameters. Adding team membership to a user that is already a member does not +affect the membership. ``` POST /projects/:id/members @@ -166,9 +195,15 @@ Parameters: + `user_id` (required) - The ID of a user to add + `access_level` (required) - Project access level -Will return status `201 Created` on success, or `404 Not found` on fail. +Return Values: -## Edit project team member ++ `200 Ok` on success and the added user, even if the user is already team member ++ `400 Bad Request` if the required attribute access_level is not given ++ `404 Not Found` if a resource can not be found, e.g. project with ID not available ++ `422 Unprocessable Entity` if an unknown access_level is given + + +### Edit project team member Update project team member to specified access level. @@ -182,9 +217,15 @@ Parameters: + `user_id` (required) - The ID of a team member + `access_level` (required) - Project access level -Will return status `200 OK` on success, or `404 Not found` on fail. +Return Values: -## Remove project team member ++ `200 Ok` on succes and the modified team member ++ `400 Bad Request` if the required attribute access_level is not given ++ `404 Not Found` if a resource can not be found, e.g. project with ID not available ++ `422 Unprocessable Entity` if an unknown access_level is given + + +### Remove project team member Removes user from project team. @@ -197,14 +238,22 @@ Parameters: + `id` (required) - The ID of a project + `user_id` (required) - The ID of a team member -Status code `200 OK` will be returned on success. This method is idempotent and call be called multiple -times with the same parameters. Revoking team membership for a user who is not currently a team member is -considered success. Please note that the returned JSON currently differs slightly. Thus you should not +Return Values: + ++ `200 Ok` on success ++ `404 Not Found` if either project or user can not be found + +This method is idempotent and can be called multiple times with the same parameters. +Revoking team membership for a user who is not currently a team member is considered success. +Please note that the returned JSON currently differs slightly. Thus you should not rely on the returned JSON structure. -## List project hooks -Get list for project hooks +## Hooks + +### List project hooks + +Get list of project hooks. ``` GET /projects/:id/hooks @@ -214,26 +263,42 @@ Parameters: + `id` (required) - The ID of a project -Will return hooks with status `200 OK` on success, or `404 Not found` on fail. +Return values: -## Get project hook ++ `200 Ok` on success with a list of hooks ++ `404 Not Found` if project can not be found -Get hook for project + +### Get project hook + +Get a specific hook for project. ``` GET /projects/:id/hooks/:hook_id ``` -Parameters:ยง +Parameters: + `id` (required) - The ID of a project + `hook_id` (required) - The ID of a project hook -Will return hook with status `200 OK` on success, or `404 Not found` on fail. +```json +{ + "id": 1, + "url": "http://example.com/hook", + "created_at": "2012-10-12T17:04:47Z" +} +``` -## Add project hook +Return values: -Add hook to project ++ `200 Ok` on sucess and the hook with the given ID ++ `404 Not Found` if the hook can not be found + + +### Add project hook + +Adds a hook to project. ``` POST /projects/:id/hooks @@ -244,11 +309,17 @@ Parameters: + `id` (required) - The ID of a project + `url` (required) - The hook URL -Will return status `201 Created` on success, or `404 Not found` on fail. +Return values: -## Edit project hook ++ `201 Created` on success and the newly created hook ++ `400 Bad Request` if url is not given ++ `404 Not Found` if project with ID not found ++ `422 Unprocessable Entity` if the url is invalid (must begin with `http` or `https`) -Edit hook for project + +### Edit project hook + +Edits a hook for project. ``` PUT /projects/:id/hooks/:hook_id @@ -260,12 +331,18 @@ Parameters: + `hook_id` (required) - The ID of a project hook + `url` (required) - The hook URL -Will return status `201 Created` on success, or `404 Not found` on fail. +Return values: + ++ `200 Ok` on success and the modified hook (see JSON response above) ++ `400 Bad Request` if the url attribute is not given ++ `404 Not Found` if project or hook can not be found ++ `422 Unprocessable Entity` if the url is invalid (must begin with `http` or `https`) -## Delete project hook +### Delete project hook -Delete hook from project +Removes a hook from project. This is an idempotent method and can be called multiple times. +Either the hook is available or not. ``` DELETE /projects/:id/hooks @@ -276,4 +353,10 @@ Parameters: + `id` (required) - The ID of a project + `hook_id` (required) - The ID of hook to delete -Will return status `200 OK` on success, or `404 Not found` on fail. +Return values: + ++ `200 Ok` on succes ++ `404 Not Found` if the project can not be found + +Note the JSON response differs if the hook is available or not. If the project hook +is available before it is returned in the JSON response or an empty response is returned. From 5417fbfecdfded18e89e55e56022b666d1a0e13f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 14 Feb 2013 21:00:05 +0100 Subject: [PATCH 29/49] Test to check 404 error when project id not found --- spec/requests/api/projects_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 96f58dde..486b63e7 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -195,6 +195,11 @@ describe Gitlab::API do json_response.count.should == 1 json_response.first['email'].should == user.email end + + it "should return a 404 error if id not found" do + get api("/projects/9999/members", user) + response.status.should == 404 + end end describe "GET /projects/:id/members/:user_id" do From 99739a58c397ac619c62b0c19162c4656e55ce24 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 15 Feb 2013 13:54:26 +0100 Subject: [PATCH 30/49] API documentation extended with infos to project branches --- doc/api/projects.md | 77 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index a36890a4..284aca4f 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -360,3 +360,80 @@ Return values: Note the JSON response differs if the hook is available or not. If the project hook is available before it is returned in the JSON response or an empty response is returned. + + +## Branches + +### List branches + +Lists all branches of a project. + +``` +GET /projects/:id/repository/branches +``` + +Parameters: + ++ `id` (required) - The ID of the project + +Return values: + ++ `200 Ok` on success and a list of branches ++ `404 Not Found` if project is not found + + +### List single branch + +Lists a specific branch of a project. + +``` +GET /projects/:id/repository/branches/:branch +``` + +Parameters: + ++ `id` (required) - The ID of the project. ++ `branch` (required) - The name of the branch. + +Return values: + ++ `200 Ok` on success ++ `404 Not Found` if either project with ID or branch could not be found + + +### Protect single branch + +Protects a single branch of a project. + +``` +PUT /projects/:id/repository/branches/:branch/protect +``` + +Parameters: + ++ `id` (required) - The ID of the project. ++ `branch` (required) - The name of the branch. + +Return values: + ++ `200 Ok` on success ++ `404 Not Found` if either project or branch could not be found + + +### Unprotect single branch + +Unprotects a single branch of a project. + +``` +PUT /projects/:id/repository/branches/:branch/unprotect +``` + +Parameters: + ++ `id` (required) - The ID of the project. ++ `branch` (required) - The name of the branch. + +Return values: + ++ `200 Ok` on success ++ `404 Not Found` if either project or branch could not be found From beb00af0c16c5b28b60043a6d42e09517ecd2c08 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 15 Feb 2013 18:50:52 +0100 Subject: [PATCH 31/49] API documentation extended with snippets, tags and commits Documentation is updated with information how to handle snippets or how to access tags and commits. Nearly all project specific functions are now described in the documentation. A few previous entries have been updated with status codes, e.g. `401 Unauthorized`. --- doc/api/projects.md | 154 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 1 deletion(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 284aca4f..d37d3acf 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -197,8 +197,9 @@ Parameters: Return Values: -+ `200 Ok` on success and the added user, even if the user is already team member ++ `201 Created` on success and the added user is returned, even if the user is already team member + `400 Bad Request` if the required attribute access_level is not given ++ `401 Unauthorized` if the user is not allowed to add a new team member + `404 Not Found` if a resource can not be found, e.g. project with ID not available + `422 Unprocessable Entity` if an unknown access_level is given @@ -221,6 +222,7 @@ Return Values: + `200 Ok` on succes and the modified team member + `400 Bad Request` if the required attribute access_level is not given ++ `401 Unauthorized` if the user is not allowed to modify a team member + `404 Not Found` if a resource can not be found, e.g. project with ID not available + `422 Unprocessable Entity` if an unknown access_level is given @@ -241,6 +243,7 @@ Parameters: Return Values: + `200 Ok` on success ++ `401 Unauthorized` if user is not allowed to remove a team member + `404 Not Found` if either project or user can not be found This method is idempotent and can be called multiple times with the same parameters. @@ -266,6 +269,7 @@ Parameters: Return values: + `200 Ok` on success with a list of hooks ++ `401 Unauthorized` if user is not allowed to get list of hooks + `404 Not Found` if project can not be found @@ -437,3 +441,151 @@ Return values: + `200 Ok` on success + `404 Not Found` if either project or branch could not be found + + +### List tags + +Lists all tags of a project. + +``` +GET /projects/:id/repository/tags +``` + +Parameters: + ++ `id` (required) - The ID of the project + +Return values: + ++ `200 Ok` on success and a list of tags ++ `404 Not Found` if project with id not found + + +### List commits + +Lists all commits with pagination. If the optional `ref_name` name is not given the commits of +the default branch (usually master) are returned. + +``` +GET /projects/:id/repository/commits +``` + +Parameters: + ++ `id` (required) - The Id of the project ++ `ref_name` (optional) - The name of a repository branch or tag ++ `page` (optional) - The page of commits to return (`0` default) ++ `per_page` (optional) - The number of commits per page (`20` default) + +Returns values: + ++ `200 Ok` on success and a list with commits ++ `404 Not Found` if project with id or the branch with `ref_name` not found + + +## Snippets + +### List snippets + +Lists the snippets of a project. + +``` +GET /projects/:id/snippets +``` + +Parameters: + ++ `id` (required) - The ID of the project + +Return values: + ++ `200 Ok` on success and the list of snippets ++ `404 Not Found` if project with id not found + + +### List single snippet + +Lists a single snippet of a project + +``` +GET /projects/:id/snippets/:snippet_id +``` + +Parameters: + ++ `id` (required) - The ID of the project ++ `snippet_id` (required) - The ID of the snippet + +Return values: + ++ `200 Ok` on success and the project snippet ++ `404 Not Found` if project ID or snippet ID not found + + +### Create snippet + +Creates a new project snippet. + +``` +POST /projects/:id/snippets +``` + +Parameters: + ++ `id` (required) - The ID of the project ++ `title` (required) - The title of the new snippet ++ `file_name` (required) - The file name of the snippet ++ `code` (required) - The content of the snippet ++ `lifetime` (optional) - The expiration date of a snippet + +Return values: + ++ `201 Created` on success and the new snippet ++ `400 Bad Request` if one of the required attributes is missing ++ `401 Unauthorized` if it is not allowed to post a new snippet ++ `404 Not Found` if the project ID is not found + + +### Update snippet + +Updates an existing project snippet. + +``` +PUT /projects/:id/snippets/:snippet_id +``` + +Parameters: + ++ `id` (required) - The ID of the project ++ `snippet_id` (required) - The id of the project snippet ++ `title` (optional) - The new title of the project snippet ++ `file_name` (optional) - The new file name of the project snippet ++ `lifetime` (optional) - The new expiration date of the snippet ++ `code` (optional) - The content of the snippet + +Return values: + ++ `200 Ok` on success and the content of the updated snippet ++ `401 Unauthorized` if the user is not allowed to modify the snippet ++ `404 Not Found` if project ID or snippet ID is not found + + +## Delete snippet + +Deletes a project snippet. This is an idempotent function call and returns `200 Ok` +even if the snippet with the id is not available. + +``` +DELETE /projects/:id/snippets/:snippet_id +``` + +Paramaters: + ++ `id` (required) - The ID of the project ++ `snippet_id` (required) - The ID of the snippet + +Return values: + ++ `200 Ok` on success, if the snippet got deleted it is returned, if not available then an empty JSON response ++ `401 Unauthorized` if the user is not allowed to remove the snippet ++ `404 Not Found` if the project ID not found From da040fc1348eb7747dd18084a2b12967f7c2b759 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Mon, 18 Feb 2013 11:15:26 +0100 Subject: [PATCH 32/49] API documentation expanded with status code information Information to return codes added to projects and users documentation. --- doc/api/projects.md | 5 +++++ doc/api/users.md | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index d37d3acf..16521917 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -57,6 +57,11 @@ GET /projects ] ``` +Return values: + ++ `200 Ok` on success and a list of projects ++ `401 Unauthorized` if the user is not allowed to access projects + ### Get single project diff --git a/doc/api/users.md b/doc/api/users.md index b94d7c0f..e5893638 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -43,6 +43,12 @@ GET /users ] ``` +Return values: + ++ `200 Ok` on success and a list with all users ++ `401 Unauthorized` if user is not allowed to access the list + + ## Single user Get a single user. @@ -74,6 +80,13 @@ Parameters: } ``` +Return values: + ++ `200 Ok` on success and the user entry ++ `401 Unauthorized` if it is not allowed to access the user ++ `404 Not Found` if the user with ID is not found + + ## User creation Create user. Available only for admin From 1b97a2eee8b89320de891e3ae8496adfa7f3a84b Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 20 Feb 2013 12:10:51 +0100 Subject: [PATCH 33/49] API: fixes return codes, documentation updated with status codes, tests added The users API updated with return codes, e.g. if required parameters are missing a `400 Bad Request` error is returned instead of `404`. Fixes return codes of functions, e.g. deletion of a ssh key is an idempotent function now. The API documentation is updated to reflect the current status of the API. Descriptions are more detailed and complete, infos to return values are added to all functions. --- doc/api/users.md | 118 +++++++++++++++++++++++------- lib/api/users.rb | 26 +++++-- spec/requests/api/users_spec.rb | 125 ++++++++++++++++++++++++++++---- 3 files changed, 224 insertions(+), 45 deletions(-) diff --git a/doc/api/users.md b/doc/api/users.md index e5893638..96aebffa 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -88,36 +88,47 @@ Return values: ## User creation -Create user. Available only for admin + +Creates a new user. Note only administrators can create new users. ``` POST /users ``` Parameters: -+ `email` (required) - Email -+ `password` (required) - Password -+ `username` (required) - Username -+ `name` (required) - Name -+ `skype` - Skype ID -+ `linkedin` - Linkedin -+ `twitter` - Twitter account -+ `projects_limit` - Number of projects user can create -+ `extern_uid` - External UID -+ `provider` - External provider name -+ `bio` - User's bio -Will return created user with status `201 Created` on success, or `404 Not -found` on fail. ++ `email` (required) - Email ++ `password` (required) - Password ++ `username` (required) - Username ++ `name` (required) - Name ++ `skype` (optional) - Skype ID ++ `linkedin` (optional) - Linkedin ++ `twitter` (optional) - Twitter account ++ `projects_limit` (optional) - Number of projects user can create ++ `extern_uid` (optional) - External UID ++ `provider` (optional) - External provider name ++ `bio` (optional) - User's bio + +Return values: + ++ `201 Created` on success and returns the new user ++ `400 Bad Request` if one of the required attributes is missing from the request ++ `401 Unauthorized` if the user is not authorized ++ `403 Forbidden` if the user is not allowed to create a new user (must be admin) ++ `404 Not Found` if something else fails ++ `409 Conflict` if a user with the same email address or username already exists + ## User modification -Modify user. Available only for admin + +Modifies an existing user. Only administrators can change attributes of a user. ``` PUT /users/:id ``` Parameters: + + `email` - Email + `username` - Username + `name` - Name @@ -130,23 +141,42 @@ Parameters: + `provider` - External provider name + `bio` - User's bio +Return values: + ++ `200 Ok` on success and returns the new user ++ `401 Unauthorized` if the user is not authorized ++ `403 Forbidden` if the user is not allowed to create a new user (must be admin) ++ `404 Not Found` if something else fails + +Note, at the moment this method does only return a 404 error, even in cases where a 409 (Conflict) would +be more appropriate, e.g. when renaming the email address to some exsisting one. -Will return created user with status `200 OK` on success, or `404 Not -found` on fail. ## User deletion -Delete user. Available only for admin + +Deletes a user. Available only for administrators. This is an idempotent function, calling this function +for a non-existent user id still returns a status code `200 Ok`. The JSON response differs if the user +was actually deleted or not. In the former the user is returned and in the latter not. ``` DELETE /users/:id ``` -Will return deleted user with status `200 OK` on success, or `404 Not -found` on fail. +Parameters: + ++ `id` (required) - The ID of the user + +Return values: + ++ `200 Ok` on success and returns the deleted user ++ `401 Unauthorized` if the user is not authorized ++ `403 Forbidden` if the user is not allowed to create a new user (must be admin) ++ `404 Not Found` if user with ID not found or something else fails + ## Current user -Get currently authenticated user. +Gets currently authenticated user. ``` GET /user @@ -169,6 +199,13 @@ GET /user } ``` +Return values: + ++ `200 Ok` on success and returns the current user ++ `401 Unauthorized` if the user is not authorized ++ `404 Not Found` if something else fails + + ## List SSH keys Get a list of currently authenticated user's SSH keys. @@ -196,6 +233,17 @@ GET /user/keys ] ``` +Parameters: + ++ **none** + +Return values: + ++ `200 Ok` on success and a list of ssh keys ++ `401 Unauthorized` if the user is not authenticated ++ `404 Not Found` if something else fails + + ## Single SSH key Get a single key. @@ -217,9 +265,17 @@ Parameters: soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" } ``` + +Return values: + ++ `200 Ok` on success and the ssh key with ID ++ `401 Unauthorized` if it is not allowed to access the user ++ `404 Not Found` if the ssh key with ID not found + + ## Add SSH key -Create new key owned by currently authenticated user +Creates a new key owned by the currently authenticated user. ``` POST /user/keys @@ -230,12 +286,18 @@ Parameters: + `title` (required) - new SSH Key's title + `key` (required) - new SSH key -Will return created key with status `201 Created` on success, or `404 Not -found` on fail. +Return values: + ++ `201 Created` on success and the added key ++ `400 Bad Request` if one of the required attributes is not given ++ `401 Unauthorized` if user is not authorized to add ssh key ++ `404 Not Found` if something else fails + ## Delete SSH key -Delete key owned by currently authenticated user +Deletes key owned by currently authenticated user. This is an idempotent function and calling it on a key that is already +deleted or not available results in `200 Ok`. ``` DELETE /user/keys/:id @@ -245,4 +307,8 @@ Parameters: + `id` (required) - SSH key ID -Will return `200 OK` on success, or `404 Not Found` on fail. +Return values: + ++ `200 Ok` on success ++ `401 Unauthorized` if user is not allowed to delete they key ++ `404 Not Found` if something else fails diff --git a/lib/api/users.rb b/lib/api/users.rb index 7ea90c75..b9dce58a 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -41,6 +41,12 @@ module Gitlab # POST /users post do authenticated_as_admin! + + bad_request!(:email) if !params.has_key? :email + bad_request!(:password) if !params.has_key? :password + bad_request!(:name) if !params.has_key? :name + bad_request!(:username) if !params.has_key? :username + attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] user = User.new attrs, as: :admin if user.save @@ -67,10 +73,12 @@ module Gitlab # PUT /users/:id put ":id" do authenticated_as_admin! - attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] - user = User.find_by_id(params[:id]) - if user && user.update_attributes(attrs) + attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] + user = User.find(params[:id]) + not_found!("User not found") unless user + + if user.update_attributes(attrs) present user, with: Entities::User else not_found! @@ -127,6 +135,9 @@ module Gitlab # Example Request: # POST /user/keys post "keys" do + bad_request!(:title) unless params[:title].present? + bad_request!(:key) unless params[:key].present? + attrs = attributes_for_keys [:title, :key] key = current_user.keys.new attrs if key.save @@ -136,15 +147,18 @@ module Gitlab end end - # Delete existed ssh key of currently authenticated user + # Delete existing ssh key of currently authenticated user # # Parameters: # id (required) - SSH Key ID # Example Request: # DELETE /user/keys/:id delete "keys/:id" do - key = current_user.keys.find params[:id] - key.delete + begin + key = current_user.keys.find params[:id] + key.delete + rescue + end end end end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 1645117e..b0cf1265 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -31,26 +31,69 @@ describe Gitlab::API do response.status.should == 200 json_response['email'].should == user.email end + + it "should return a 401 if unauthenticated" do + get api("/users/9998") + response.status.should == 401 + end + + it "should return a 404 error if user id not found" do + get api("/users/9999", user) + response.status.should == 404 + end end describe "POST /users" do before{ admin } - it "should not create invalid user" do - post api("/users", admin), { email: "invalid email" } - response.status.should == 404 - end - it "should create user" do expect { post api("/users", admin), attributes_for(:user, projects_limit: 3) }.to change { User.count }.by(1) end + it "should return 201 Created on success" do + post api("/users", admin), attributes_for(:user, projects_limit: 3) + response.status.should == 201 + end + + it "should not create user with invalid email" do + post api("/users", admin), { email: "invalid email", password: 'password' } + response.status.should == 400 + end + + it "should return 400 error if password not given" do + post api("/users", admin), { email: 'test@example.com' } + response.status.should == 400 + end + + it "should return 400 error if email not given" do + post api("/users", admin), { password: 'pass1234' } + response.status.should == 400 + end + it "shouldn't available for non admin users" do post api("/users", user), attributes_for(:user) response.status.should == 403 end + + context "with existing user" do + before { post api("/users", admin), { email: 'test@example.com', password: 'password', username: 'test' } } + + it "should not create user with same email" do + expect { + post api("/users", admin), { email: 'test@example.com', password: 'password' } + }.to change { User.count }.by(0) + end + + it "should return 409 conflict error if user with email exists" do + post api("/users", admin), { email: 'test@example.com', password: 'password' } + end + + it "should return 409 conflict error if same username exists" do + post api("/users", admin), { email: 'foo@example.com', password: 'pass', username: 'test' } + end + end end describe "GET /users/sign_up" do @@ -86,7 +129,7 @@ describe Gitlab::API do describe "PUT /users/:id" do before { admin } - it "should update user" do + it "should update user with new bio" do put api("/users/#{user.id}", admin), {bio: 'new test bio'} response.status.should == 200 json_response['bio'].should == 'new test bio' @@ -108,6 +151,25 @@ describe Gitlab::API do put api("/users/999999", admin), {bio: 'update should fail'} response.status.should == 404 end + + context "with existing user" do + before { + post api("/users", admin), { email: 'test@example.com', password: 'password', username: 'test', name: 'test' } + post api("/users", admin), { email: 'foo@bar.com', password: 'password', username: 'john', name: 'john' } + @user_id = User.all.last.id + } + +# it "should return 409 conflict error if email address exists" do +# put api("/users/#{@user_id}", admin), { email: 'test@example.com' } +# response.status.should == 409 +# end +# +# it "should return 409 conflict error if username taken" do +# @user_id = User.all.last.id +# put api("/users/#{@user_id}", admin), { username: 'test' } +# response.status.should == 409 +# end + end end describe "DELETE /users/:id" do @@ -120,6 +182,11 @@ describe Gitlab::API do json_response['email'].should == user.email end + it "should not delete for unauthenticated user" do + delete api("/users/#{user.id}") + response.status.should == 401 + end + it "shouldn't available for non admin users" do delete api("/users/#{user.id}", user) response.status.should == 403 @@ -137,6 +204,11 @@ describe Gitlab::API do response.status.should == 200 json_response['email'].should == user.email end + + it "should return 401 error if user is unauthenticated" do + get api("/user") + response.status.should == 401 + end end describe "GET /user/keys" do @@ -172,19 +244,38 @@ describe Gitlab::API do get api("/user/keys/42", user) response.status.should == 404 end + + it "should return 404 error if admin accesses user's ssh key" do + user.keys << key + user.save + admin + get api("/user/keys/#{key.id}", admin) + response.status.should == 404 + end end describe "POST /user/keys" do - it "should not create invalid ssh key" do - post api("/user/keys", user), { title: "invalid key" } - response.status.should == 404 - end - it "should create ssh key" do key_attrs = attributes_for :key expect { post api("/user/keys", user), key_attrs }.to change{ user.keys.count }.by(1) + response.status.should == 201 + end + + it "should return a 401 error if unauthorized" do + post api("/user/keys"), title: 'some title', key: 'some key' + response.status.should == 401 + end + + it "should not create ssh key without key" do + post api("/user/keys", user), title: 'title' + response.status.should == 400 + end + + it "should not create ssh key without title" do + post api("/user/keys", user), key: "somekey" + response.status.should == 400 end end @@ -195,11 +286,19 @@ describe Gitlab::API do expect { delete api("/user/keys/#{key.id}", user) }.to change{user.keys.count}.by(-1) + response.status.should == 200 end - it "should return 404 Not Found within invalid ID" do + it "should return sucess if key ID not found" do delete api("/user/keys/42", user) - response.status.should == 404 + response.status.should == 200 + end + + it "should return 401 error if unauthorized" do + user.keys << key + user.save + delete api("/user/keys/#{key.id}") + response.status.should == 401 end end end From 512d826cc3e89bb577f485d4767d91185f3f0556 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 20 Feb 2013 14:15:04 +0100 Subject: [PATCH 34/49] API: fixes test if project limit is reached Fixes a test that checks if the project limit is reached. --- spec/models/project_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 5c27f363..cd58ffeb 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -64,7 +64,7 @@ describe Project do it "should not allow new projects beyond user limits" do project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1)) project.should_not be_valid - project.errors[:base].first.should match(/Your own projects limit is 1/) + project.errors[:limit_reached].first.should match(/Your own projects limit is 1/) end end From 33c1463645b51bcb26932e4825df0ce8fee6c729 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 20 Feb 2013 22:17:05 +0100 Subject: [PATCH 35/49] API: fixes return codes for notes, documentation updated The notes API documentation updated with return codes. API now returns `400 Bad Request` if required attributes are not present. Return codes are documented now, also tested in added tests. The documentation now reflects the current state of the API. --- doc/api/notes.md | 269 +++++++++++++++++++++++--------- lib/api/notes.rb | 5 + spec/requests/api/notes_spec.rb | 46 +++++- 3 files changed, 241 insertions(+), 79 deletions(-) diff --git a/doc/api/notes.md b/doc/api/notes.md index eef4b63f..6a6a99aa 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -1,4 +1,4 @@ -## List notes +## Wall ### List project wall notes @@ -30,50 +30,15 @@ Parameters: + `id` (required) - The ID of a project -### List merge request notes +Return values: -Get a list of merge request notes. ++ `200 Ok` on success and a list of notes ++ `401 Unauthorized` if user is not authorized to access this page -``` -GET /projects/:id/merge_requests/:merge_request_id/notes -``` -Parameters: +### Get single wall note -+ `id` (required) - The ID of a project -+ `merge_request_id` (required) - The ID of an merge request - -### List issue notes - -Get a list of issue notes. - -``` -GET /projects/:id/issues/:issue_id/notes -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `issue_id` (required) - The ID of an issue - -### List snippet notes - -Get a list of snippet notes. - -``` -GET /projects/:id/snippets/:snippet_id/notes -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `snippet_id` (required) - The ID of a snippet - -## Single note - -### Single wall note - -Get a wall note. +Returns a single wall note. ``` GET /projects/:id/notes/:note_id @@ -84,9 +49,60 @@ Parameters: + `id` (required) - The ID of a project + `note_id` (required) - The ID of a wall note -### Single issue note +Return values: -Get an issue note. ++ `200 Ok` on success and the wall note (see example at `GET /projects/:id/notes`) ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if note ID not found + + +### Create new wall note + +Creates a new wall note. + +``` +POST /projects/:id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `body` (required) - The content of a note + +Return values: + ++ `201 Created` on success and the new wall note ++ `400 Bad Request` if attribute body is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if something else fails + + + +## Issues + +### List project issue notes + +Gets a list of all notes for a single issue. + +``` +GET /projects/:id/issues/:issue_id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `issue_id` (required) - The ID of an issue + +Return values: + ++ `200 Ok` on success and a list of notes for a single issue ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or issue ID not found + + +### Get single issue note + +Returns a single note for a specific project issue ``` GET /projects/:id/issues/:issue_id/notes/:note_id @@ -98,41 +114,16 @@ Parameters: + `issue_id` (required) - The ID of a project issue + `note_id` (required) - The ID of an issue note -### Single snippet note +Return values: -Get a snippet note. - -``` -GET /projects/:id/issues/:snippet_id/notes/:note_id -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `snippet_id` (required) - The ID of a project snippet -+ `note_id` (required) - The ID of an snippet note - -## New note - -### New wall note - -Create a new wall note. - -``` -POST /projects/:id/notes -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `body` (required) - The content of a note - -Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. ++ `200 Ok` on success and the single issue note ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID, issue ID or note ID is not found -### New issue note +### Create new issue note -Create a new issue note. +Creates a new note to a single project issue. ``` POST /projects/:id/issues/:issue_id/notes @@ -144,11 +135,61 @@ Parameters: + `issue_id` (required) - The ID of an issue + `body` (required) - The content of a note -Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. +Return values: -### New snippet note ++ `201 Created` on succes and the created note ++ `400 Bad Request` if the required attribute body is not given ++ `401 Unauthorized` if the user is not authenticated ++ `404 Not Found` if the project ID or the issue ID not found -Create a new snippet note. + + +## Snippets + +### List all snippet notes + +Gets a list of all notes for a single snippet. Snippet notes are comments users can post to a snippet. + +``` +GET /projects/:id/snippets/:snippet_id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `snippet_id` (required) - The ID of a project snippet + +Return values: + ++ `200 Ok` on success and a list of notes for a single snippet ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or issue ID not found + + +### Get single snippet note + +Returns a single note for a given snippet. + +``` +GET /projects/:id/snippets/:snippet_id/notes/:note_id +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `snippet_id` (required) - The ID of a project snippet ++ `note_id` (required) - The ID of an snippet note + +Return values: + ++ `200 Ok` on success and the single snippet note ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID, snippet ID or note ID is not found + + +### Create new snippet note + +Creates a new note for a single snippet. Snippet notes are comments users can post to a snippet. ``` POST /projects/:id/snippets/:snippet_id/notes @@ -160,4 +201,76 @@ Parameters: + `snippet_id` (required) - The ID of an snippet + `body` (required) - The content of a note -Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. +Return values: + ++ `201 Created` on success and the new snippet note ++ `400 Bad Request` if the required attribute body not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or snippet ID not found + + + +## Merge Requests + +### List all merge request notes + +Gets a list of all notes for a single merge request. + +``` +GET /projects/:id/merge_requests/:merge_request_id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `merge_request_id` (required) - The ID of a project merge request + +Return values: + ++ `200 Ok` on success and a list of notes for a single merge request ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or merge request ID not found + + +### Get single merge request note + +Returns a single note for a given merge request. + +``` +GET /projects/:id/merge_requests/:merge_request_id/notes/:note_id +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `merge_request_id` (required) - The ID of a project merge request ++ `note_id` (required) - The ID of a merge request note + +Return values: + ++ `200 Ok` on success and the single merge request note ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID, merge request ID or note ID is not found + + +### Create new merge request note + +Creates a new note for a single merge request. + +``` +POST /projects/:id/merge_requests/:merge_request_id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `merge_request_id` (required) - The ID of a merge request ++ `body` (required) - The content of a note + +Return values: + ++ `201 Created` on success and the new merge request note ++ `400 Bad Request` if the required attribute body not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or merge request ID not found + diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 56de6e09..953514b6 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -37,6 +37,8 @@ module Gitlab # Example Request: # POST /projects/:id/notes post ":id/notes" do + bad_request!(:body) unless params[:body].present? + @note = user_project.notes.new(note: params[:body]) @note.author = current_user @@ -91,6 +93,9 @@ module Gitlab # POST /projects/:id/issues/:noteable_id/notes # POST /projects/:id/snippets/:noteable_id/notes post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do + bad_request!(:"#{noteable_id_str}") unless params[:"#{noteable_id_str}"].present? + bad_request!(:body) unless params[:body].present? + @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"]) @note = @noteable.notes.new(note: params[:body]) @note.author = current_user diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index d382d7d9..92ac5bef 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -52,7 +52,12 @@ describe Gitlab::API do json_response['body'].should == 'hi!' end - it "should return a 400 error if body is missing" do + it "should return 401 unauthorized error" do + post api("/projects/#{project.id}/notes") + response.status.should == 401 + end + + it "should return a 400 bad request if body is missing" do post api("/projects/#{project.id}/notes", user) response.status.should == 400 end @@ -94,6 +99,18 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['body'].should == merge_request_note.note end + + it "should return a 404 error if merge request id not found" do + get api("/projects/#{project.id}/merge_requests/4444/notes", user) + response.status.should == 404 + end + end + + context "when notable is invalid" do + it "should return a 404 error" do + get api("/projects/#{project.id}/unknown/#{snippet.id}/notes", user) + response.status.should == 404 + end end end @@ -133,6 +150,16 @@ describe Gitlab::API do json_response['body'].should == 'hi!' json_response['author']['email'].should == user.email end + + it "should return a 400 bad request error if body not given" do + post api("/projects/#{project.id}/issues/#{issue.id}/notes", user) + response.status.should == 400 + end + + it "should return a 401 unauthorized error if user not authenticated" do + post api("/projects/#{project.id}/issues/#{issue.id}/notes"), body: 'hi!' + response.status.should == 401 + end end context "when noteable is a Snippet" do @@ -142,6 +169,23 @@ describe Gitlab::API do json_response['body'].should == 'hi!' json_response['author']['email'].should == user.email end + + it "should return a 400 bad request error if body not given" do + post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user) + response.status.should == 400 + end + + it "should return a 401 unauthorized error if user not authenticated" do + post api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!' + response.status.should == 401 + end + end + + context "when noteable is invalid" do + it "should return a 404 error" do + post api("/projects/#{project.id}/invalid/#{snippet.id}/notes", user) + response.status.should == 404 + end end end end From 4a60c377b8cd531800757894e26cec1ac649046f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 20 Feb 2013 22:51:59 +0100 Subject: [PATCH 36/49] API documentation update for milestones Updated the milestones API documentation and added return codes descriptions. --- doc/api/milestones.md | 40 +++++++++++++++++++++++----- lib/api/milestones.rb | 18 ++----------- spec/requests/api/milestones_spec.rb | 15 ++++++++--- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/doc/api/milestones.md b/doc/api/milestones.md index 73d29afc..9bb27271 100644 --- a/doc/api/milestones.md +++ b/doc/api/milestones.md @@ -1,6 +1,6 @@ ## List project milestones -Get a list of project milestones. +Returns a list of project milestones. ``` GET /projects/:id/milestones @@ -10,9 +10,16 @@ Parameters: + `id` (required) - The ID of a project -## Single milestone +Return values: -Get a single project milestone. ++ `200 Ok` on success and the list of project milestones ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + +## Get single milestone + +Gets a single project milestone. ``` GET /projects/:id/milestones/:milestone_id @@ -23,9 +30,16 @@ Parameters: + `id` (required) - The ID of a project + `milestone_id` (required) - The ID of a project milestone -## New milestone +Return values: -Create a new project milestone. ++ `200 Ok` on success and the single milestone ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + +## Create new milestone + +Creates a new project milestone. ``` POST /projects/:id/milestones @@ -38,9 +52,17 @@ Parameters: + `description` (optional) - The description of the milestone + `due_date` (optional) - The due date of the milestone +Return values: + ++ `201 Created` on success and the new milestone ++ `400 Bad Request` if the required attribute title is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + ## Edit milestone -Update an existing project milestone. +Updates an existing project milestone. ``` PUT /projects/:id/milestones/:milestone_id @@ -54,3 +76,9 @@ Parameters: + `description` (optional) - The description of a milestone + `due_date` (optional) - The due date of the milestone + `closed` (optional) - The status of the milestone + +Return values: + ++ `200 Ok` on success and the updated milestone ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or milestone ID not found diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 7f8fe053..ff98f005 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -4,20 +4,6 @@ module Gitlab before { authenticate! } resource :projects do - - helpers do - # If an error occurs this helper method handles error codes for a given milestone - # - # Parameters: - # milestone_errors (required) - The erros collection of a milestone - # - def handle_milestone_errors(milestone_errors) - if milestone_errors[:title].any? - bad_request!(:title) - end - end - end - # Get a list of project milestones # # Parameters: @@ -56,12 +42,13 @@ module Gitlab post ":id/milestones" do authorize! :admin_milestone, user_project + bad_request!(:title) unless params[:title].present? + attrs = attributes_for_keys [:title, :description, :due_date] @milestone = user_project.milestones.new attrs if @milestone.save present @milestone, with: Entities::Milestone else - handle_milestone_errors(@milestone.errors) not_found! end end @@ -85,7 +72,6 @@ module Gitlab if @milestone.update_attributes attrs present @milestone, with: Entities::Milestone else - handle_milestone_errors(@milestone.errors) not_found! end end diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index 00e800e8..c379e8a5 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -16,6 +16,11 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['title'].should == milestone.title end + + it "should return a 401 error if user not authenticated" do + get api("/projects/#{project.id}/milestones") + response.status.should == 401 + end end describe "GET /projects/:id/milestones/:milestone_id" do @@ -25,6 +30,11 @@ describe Gitlab::API do json_response['title'].should == milestone.title end + it "should return 401 error if user not authenticated" do + get api("/projects/#{project.id}/milestones/#{milestone.id}") + response.status.should == 401 + end + it "should return a 404 error if milestone id not found" do get api("/projects/#{project.id}/milestones/1234", user) response.status.should == 404 @@ -33,8 +43,7 @@ describe Gitlab::API do describe "POST /projects/:id/milestones" do it "should create a new project milestone" do - post api("/projects/#{project.id}/milestones", user), - title: 'new milestone' + post api("/projects/#{project.id}/milestones", user), title: 'new milestone' response.status.should == 201 json_response['title'].should == 'new milestone' json_response['description'].should be_nil @@ -62,7 +71,7 @@ describe Gitlab::API do json_response['title'].should == 'updated title' end - it "should return a 404 error if milestone is not found" do + it "should return a 404 error if milestone id not found" do put api("/projects/#{project.id}/milestones/1234", user), title: 'updated title' response.status.should == 404 From ce9e35c295d4df4b6a093ffef7ce0ad3f5e1a24e Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 21 Feb 2013 21:04:16 +0100 Subject: [PATCH 37/49] API: Fixes tests for changed hook deletion --- spec/requests/api/projects_spec.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 9fbdd52e..07a777d0 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -433,19 +433,14 @@ describe Gitlab::API do end it "should return success when deleting hook" do - delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id + delete api("/projects/#{project.id}/hooks/#{hook.id}", user) response.status.should == 200 end it "should return success when deleting non existent hook" do - delete api("/projects/#{project.id}/hooks", user), hook_id: 42 + delete api("/projects/#{project.id}/hooks/42", user) response.status.should == 200 end - - it "should return a 400 error if hook id not given" do - delete api("/projects/#{project.id}/hooks", user) - response.status.should == 400 - end end describe "GET /projects/:id/repository/tags" do From 9ee6c58accfd51036d7242dc51fbfec2c9abeb06 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 21 Feb 2013 21:13:46 +0100 Subject: [PATCH 38/49] API documentation updated for project snippets. The API Documentation for project snippets got infos to return codes. Tests are added to check status codes when handling project snippets. --- doc/api/snippets.md | 71 ++++++++++++++++++++++-------- spec/requests/api/projects_spec.rb | 11 +++++ 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/doc/api/snippets.md b/doc/api/snippets.md index ceb8a63d..61dbb5e4 100644 --- a/doc/api/snippets.md +++ b/doc/api/snippets.md @@ -10,9 +10,15 @@ Parameters: + `id` (required) - The ID of a project +Return values: + ++ `200 Ok` on success and a list of project snippets ++ `401 Unauthorized` if user is not authenticated + + ## Single snippet -Get a project snippet. +Get a single project snippet. ``` GET /projects/:id/snippets/:snippet_id @@ -42,22 +48,16 @@ Parameters: } ``` -## Snippet content +Return values: -Get a raw project snippet. ++ `200 Ok` on success and the project snippet ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if snippet ID not found -``` -GET /projects/:id/snippets/:snippet_id/raw -``` -Parameters: +## Create new snippet -+ `id` (required) - The ID of a project -+ `snippet_id` (required) - The ID of a project's snippet - -## New snippet - -Create a new project snippet. +Creates a new project snippet. ``` POST /projects/:id/snippets @@ -71,11 +71,17 @@ Parameters: + `lifetime` (optional) - The expiration date of a snippet + `code` (required) - The content of a snippet -Will return created snippet with status `201 Created` on success, or `404 Not found` on fail. +Return values: + ++ `201 Created` if snippet was successfully created and the snippet as JSON payload ++ `400 Bad Request` if one of the required attributes is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + ## Edit snippet -Update an existing project snippet. +Updates an existing project snippet. ``` PUT /projects/:id/snippets/:snippet_id @@ -90,11 +96,17 @@ Parameters: + `lifetime` (optional) - The expiration date of a snippet + `code` (optional) - The content of a snippet -Will return updated snippet with status `200 OK` on success, or `404 Not found` on fail. +Return values: + ++ `200 Ok` on success and the updated project snippet ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + ## Delete snippet -Delete existing project snippet. +Deletes an existing project snippet. This is an idempotent function and deleting a non-existent +snippet still returns a `200 Ok` status code. ``` DELETE /projects/:id/snippets/:snippet_id @@ -105,5 +117,28 @@ Parameters: + `id` (required) - The ID of a project + `snippet_id` (required) - The ID of a project's snippet -Status code `200` will be returned on success. +Return values: ++ `200 Ok` on success and if the snippet was deleted its content ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + +## Snippet content + +Get a raw project snippet. + +``` +GET /projects/:id/snippets/:snippet_id/raw +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `snippet_id` (required) - The ID of a project's snippet + +Return values: + ++ `200 Ok` on success and the raw snippet ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or snippet ID is not found \ No newline at end of file diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 07a777d0..8ab7d825 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -480,6 +480,11 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['title'].should == snippet.title end + + it "should return 401 error if user not authenticated" do + get api("/projects/#{project.id}/snippets") + response.status.should == 401 + end end describe "GET /projects/:id/snippets/:snippet_id" do @@ -520,6 +525,12 @@ describe Gitlab::API do title: 'api test', file_name: 'sample.rb' response.status.should == 400 end + + it "should return a 401 error if user not authenticated" do + post api("/projects/#{project.id}/snippets"), + title: 'api test', file_name: 'sample.rb', code: 'i=0' + response.status.should == 401 + end end describe "PUT /projects/:id/snippets/:shippet_id" do From e119b0a0cb33b1b7f2dafcf17c2a94af40aed833 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 11:24:12 +0100 Subject: [PATCH 39/49] API repository documentation updated, includes infos to return codes The API documentation of repository is updated and now contains infos to status codes. Code documentation is also adjusted for `GET /projects/:id/repository/commits` and includes infos to pagination attributes. Tests are updated. --- doc/api/repositories.md | 74 +++++++++++++++++++++++++----- lib/api/projects.rb | 4 +- spec/requests/api/projects_spec.rb | 20 +++----- 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index fd0ef1f5..17346278 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -1,4 +1,4 @@ -## Project repository branches +## List repository branches Get a list of repository branches from a project, sorted by name alphabetically. @@ -39,7 +39,14 @@ Parameters: ] ``` -## Project repository branch +Return values: + ++ `200 Ok`on success and a list of repository branches for the project ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project with ID not found + + +## Get single repository branch Get a single project repository branch. @@ -79,12 +86,18 @@ Parameters: } ``` -Will return status code `200` on success or `404 Not found` if the branch is not available. +Return values: + ++ `200 Ok` on success and the repository branch ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if the project ID or branch not found -## Protect a project repository branch -Protect a single project repository branch. +## Protect repository branch + +Protects a single project repository branch. This is an idempotent function, protecting an already +protected repository branch still returns a `200 Ok` status code. ``` PUT /projects/:id/repository/branches/:branch/protect @@ -122,9 +135,18 @@ Parameters: } ``` -## Unprotect a project repository branch +Return values: -Unprotect a single project repository branch. ++ `200 Ok` on success and the updated repository branch ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if the the project ID or branch not found + + + +## Unprotect repository branch + +Unprotects a single project repository branch. This is an idempotent function, unprotecting an already +unprotected repository branch still returns a `200 Ok` status code. ``` PUT /projects/:id/repository/branches/:branch/unprotect @@ -162,7 +184,15 @@ Parameters: } ``` -## Project repository tags +Return values: + ++ `200 Ok` on success and the updated repository branch ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if the project ID or the branch not found + + + +## List project repository tags Get a list of repository tags from a project, sorted by name in reverse alphabetical order. @@ -201,7 +231,14 @@ Parameters: ] ``` -## Project repository commits +Return values: + ++ `200 Ok` on success and the list of repository tags ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if the project ID not found + + +## List repository commits Get a list of repository commits in a project. @@ -212,7 +249,9 @@ GET /projects/:id/repository/commits Parameters: + `id` (required) - The ID of a project -+ `ref_name` (optional) - The name of a repository branch or tag ++ `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch ++ `page`(optional) - The page with the commits (pagination) ++ `per_page` (optional) - The number of commits per page (pagination) ```json [ @@ -235,6 +274,13 @@ Parameters: ] ``` +Return values: + ++ `200 Ok` on success and a list of commits ++ `401 Unauthorized` if the user is not authenticated ++ `404 Not Found` if the project ID not found + + ## Raw blob content Get the raw file contents for a file. @@ -249,4 +295,10 @@ Parameters: + `sha` (required) - The commit or branch name + `filepath` (required) - The path the file -Will return the raw file contents. +Return values: + ++ `200 Ok` on success and the raw content of the file ++ `400 Bad Request` if required attribute filepath is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or sha commit or branch name not found + diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 65381dac..c749c24f 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -331,7 +331,9 @@ module Gitlab # # Parameters: # id (required) - The ID of a project - # ref_name (optional) - The name of a repository branch or tag + # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used + # page (optional) - The page number of the commit pagination + # per_page (optional) - The number of elements per page used in pagination # Example Request: # GET /projects/:id/repository/commits get ":id/repository/commits" do diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 8ab7d825..9fbdd52e 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -433,14 +433,19 @@ describe Gitlab::API do end it "should return success when deleting hook" do - delete api("/projects/#{project.id}/hooks/#{hook.id}", user) + delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id response.status.should == 200 end it "should return success when deleting non existent hook" do - delete api("/projects/#{project.id}/hooks/42", user) + delete api("/projects/#{project.id}/hooks", user), hook_id: 42 response.status.should == 200 end + + it "should return a 400 error if hook id not given" do + delete api("/projects/#{project.id}/hooks", user) + response.status.should == 400 + end end describe "GET /projects/:id/repository/tags" do @@ -480,11 +485,6 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['title'].should == snippet.title end - - it "should return 401 error if user not authenticated" do - get api("/projects/#{project.id}/snippets") - response.status.should == 401 - end end describe "GET /projects/:id/snippets/:snippet_id" do @@ -525,12 +525,6 @@ describe Gitlab::API do title: 'api test', file_name: 'sample.rb' response.status.should == 400 end - - it "should return a 401 error if user not authenticated" do - post api("/projects/#{project.id}/snippets"), - title: 'api test', file_name: 'sample.rb', code: 'i=0' - response.status.should == 401 - end end describe "PUT /projects/:id/snippets/:shippet_id" do From 873db06255eae1f69644c2a0815b88c923021c8f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 12:34:45 +0100 Subject: [PATCH 40/49] API: groups documentation updated, functions return different status codes Updates the API documentation of groups with infos to return codes. The function calls in the groups API have updated documentation and return `400 Bad Request` status code if a required attribute is missing. --- doc/api/groups.md | 30 +++++++++++++++++++++++++----- lib/api/groups.rb | 11 +++++++++-- spec/requests/api/groups_spec.rb | 10 ++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/doc/api/groups.md b/doc/api/groups.md index 00a7387c..c97851a5 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -17,7 +17,14 @@ GET /groups ] ``` -## Details of group +Return values: + ++ `200 Ok` on success and list of groups ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if something fails + + +## Details of a group Get all details of a group. @@ -29,17 +36,30 @@ Parameters: + `id` (required) - The ID of a group +Return values: + ++ `200 Ok` on success and the details of a group ++ `401 Unauthorized` if user not authenticated ++ `404 Not Found` if group ID not found + + ## New group -Create a new project group. Available only for admin +Creates a new project group. Available only for admin. ``` POST /groups ``` Parameters: -+ `name` (required) - Email -+ `path` - Password -Will return created group with status `201 Created` on success, or `404 Not found` on fail. ++ `name` (required) - The name of the group ++ `path` (required) - The path of the group + +Return valueS: + ++ `201 Created` on success and the newly created group ++ `400 Bad Request` if one of the required attributes not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if something fails diff --git a/lib/api/groups.rb b/lib/api/groups.rb index a67caef0..3f213073 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -6,6 +6,9 @@ module Gitlab resource :groups do # Get a groups list # + # Parameters + # page (optional) - The page number of the groups list + # per_page (optional) - The number of elements per page # Example Request: # GET /groups get do @@ -20,12 +23,16 @@ module Gitlab # Create group. Available only for admin # # Parameters: - # name (required) - Name - # path (required) - Path + # name (required) - The name of the group + # path (required) - The path of the group # Example Request: # POST /groups post do authenticated_as_admin! + + bad_request!(:name) unless params[:name].present? + bad_request!(:path) unless params[:path].present? + attrs = attributes_for_keys [:name, :path] @group = Group.new(attrs) @group.owner = current_user diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index c39a4228..df658a8c 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -88,6 +88,16 @@ describe Gitlab::API do post api("/groups", admin), {:name => "Duplicate Test", :path => group2.path} response.status.should == 404 end + + it "should return 400 bad request error if name not given" do + post api("/groups", admin), { :path => group2.path } + response.status.should == 400 + end + + it "should return 400 bad request error if path not given" do + post api("/groups", admin), { :name => 'test' } + response.status.should == 400 + end end end end From dffc2b8a8b3ed03f12dc8f41a6f24b96f2605268 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 12:58:06 +0100 Subject: [PATCH 41/49] API: session documentation updated and test added --- doc/api/session.md | 5 +++++ spec/requests/api/session_spec.rb | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/doc/api/session.md b/doc/api/session.md index c7e57aac..5f49d989 100644 --- a/doc/api/session.md +++ b/doc/api/session.md @@ -21,3 +21,8 @@ Parameters: "blocked": true } ``` + +Return values: + ++ `201 Created` on success ++ `401 Unauthorized` if the authentication process failed, e.g. invalid password or attribute not given diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb index afae8be8..2cdb0d7e 100644 --- a/spec/requests/api/session_spec.rb +++ b/spec/requests/api/session_spec.rb @@ -35,5 +35,15 @@ describe Gitlab::API do json_response['private_token'].should be_nil end end + + context "when empty name" do + it "should return authentication error" do + post api("/session"), password: user.password + response.status.should == 401 + + json_response['email'].should be_nil + json_response['private_token'].should be_nil + end + end end end From e96d77d3dbd789981b8e85e7afba9a5908d79483 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 14:36:20 +0100 Subject: [PATCH 42/49] API: issues documentation and API functions updated The issues documentation is updated with infos to status codes and the deprecated `DELETE` function and how to close an issue. A few more tests added to check status codes of API functions. --- doc/api/issues.md | 67 ++++++++++++++++++++++++++++---- lib/api/issues.rb | 1 + spec/requests/api/issues_spec.rb | 16 ++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/doc/api/issues.md b/doc/api/issues.md index 0383b676..b782cec9 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -1,6 +1,7 @@ ## List issues -Get all issues created by authenticed user. +Get all issues created by authenticed user. This function takes pagination parameters +`page` and `per_page` to get a list of issues. ``` GET /issues @@ -68,9 +69,18 @@ GET /issues ] ``` +Return values: + ++ `200 Ok` on success and the list of issues ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if something fails + + + ## List project issues -Get a list of project issues. +Get a list of project issues. This function accepts pagination parameters `page` and `per_page` +to return the list of project issues. ``` GET /projects/:id/issues @@ -80,9 +90,16 @@ Parameters: + `id` (required) - The ID of a project +Return values: + ++ `200 Ok` on success and the list of project issues ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + ## Single issue -Get a project issue. +Gets a single project issue. ``` GET /projects/:id/issues/:issue_id @@ -133,9 +150,16 @@ Parameters: } ``` +Return values: + ++ `200 Ok` on success and the list of project issues ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or issue ID not found + + ## New issue -Create a new project issue. +Creates a new project issue. ``` POST /projects/:id/issues @@ -150,11 +174,17 @@ Parameters: + `milestone_id` (optional) - The ID of a milestone to assign issue + `labels` (optional) - Comma-separated label names for an issue -Will return created issue with status `201 Created` on success, or `404 Not found` on fail. +Return values: + ++ `201 Created` on success and the newly created project issue ++ `400 Bad Request` if the required attribute title is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + ## Edit issue -Update an existing project issue. +Updates an existing project issue. This function is also used to mark an issue as closed. ``` PUT /projects/:id/issues/:issue_id @@ -171,5 +201,28 @@ Parameters: + `labels` (optional) - Comma-separated label names for an issue + `closed` (optional) - The state of an issue (0 = false, 1 = true) -Will return updated issue with status `200 OK` on success, or `404 Not found` on fail. +Return values: ++ `200 Ok` on success and the update project issue ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or issue ID not found + + +## Delete existing issue (**Deprecated**) + +The function is deprecated and returns a `405 Method Not Allowed` +error if called. An issue gets now closed and is done by calling `PUT /projects/:id/issues/:issue_id` with +parameter `closed` set to 1. + +``` +DELETE /projects/:id/issues/:issue_id +``` + +Parameters: + ++ `id` (required) - The project ID ++ `issue_id` (required) - The ID of the issue + +Return values: + ++ `405 Method Not Allowed` is always returned, because the function is deprecated diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 70bbf47e..da966fc0 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -48,6 +48,7 @@ module Gitlab # Example Request: # POST /projects/:id/issues post ":id/issues" do + bad_request!(:title) unless params[:title].present? attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id] attrs[:label_list] = params[:labels] if params[:labels].present? @issue = user_project.issues.new attrs diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 630ac0f8..ecf0bdb7 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -41,6 +41,11 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == issue.title end + + it "should return 404 if issue id not found" do + get api("/projects/#{project.id}/issues/54321", user) + response.status.should == 404 + end end describe "POST /projects/:id/issues" do @@ -52,6 +57,11 @@ describe Gitlab::API do json_response['description'].should be_nil json_response['labels'].should == ['label', 'label2'] end + + it "should return a 400 bad request if title not given" do + post api("/projects/#{project.id}/issues", user), labels: 'label, label2' + response.status.should == 400 + end end describe "PUT /projects/:id/issues/:issue_id to update only title" do @@ -62,6 +72,12 @@ describe Gitlab::API do json_response['title'].should == 'updated title' end + + it "should return 404 error if issue id not found" do + put api("/projects/#{project.id}/issues/44444", user), + title: 'updated title' + response.status.should == 404 + end end describe "PUT /projects/:id/issues/:issue_id to update state and label" do From 3b3add35fb88578df96fe9b728ddac896ea9c944 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 15:07:42 +0100 Subject: [PATCH 43/49] API: merge request documentation updated, added return codes to functions The API documentation of merge requests contains info to status codes for all functions. Required arguments are now checked in the merge requests API functions and a `400 Bad Request` error is returned if they are not given. --- doc/api/issues.md | 2 +- doc/api/merge_requests.md | 54 ++++++++++++++++++++---- lib/api/merge_requests.rb | 9 ++-- spec/requests/api/merge_requests_spec.rb | 7 ++- 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/doc/api/issues.md b/doc/api/issues.md index b782cec9..025c6e50 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -1,7 +1,7 @@ ## List issues Get all issues created by authenticed user. This function takes pagination parameters -`page` and `per_page` to get a list of issues. +`page` and `per_page` to restrict the list of issues. ``` GET /issues diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 525c55d1..633aca78 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -1,6 +1,7 @@ ## List merge requests -Get all MR for this project. +Get all merge requests for this project. This function takes pagination parameters +`page` and `per_page` to restrict the list of merge requests. ``` GET /projects/:id/merge_requests @@ -40,9 +41,16 @@ Parameters: ] ``` -## Show MR +Return values: -Show information about MR. ++ `200 Ok` on success and the list of merge requests ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + +## Get single MR + +Shows information about a single merge request. ``` GET /projects/:id/merge_request/:merge_request_id @@ -81,10 +89,16 @@ Parameters: } ``` +Return values: + ++ `200 Ok` on success and the single merge request ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or merge request ID not found + ## Create MR -Create MR. +Creates a new merge request. ``` POST /projects/:id/merge_requests @@ -126,9 +140,18 @@ Parameters: } ``` +Return values: + ++ `201 Created` on success and the created merge request ++ `400 Bad Request` if one of the required attributes is missing ++ `401 Unauthorize` if user is not authenticated or not allowed ++ `403 Forbidden` if user is not allowed to create a merge request ++ `404 Not Found` if project ID not found or something else fails + + ## Update MR -Update MR. You can change branches, title, or even close the MR. +Updates an existing merge request. You can change branches, title, or even close the MR. ``` PUT /projects/:id/merge_request/:merge_request_id @@ -172,9 +195,18 @@ Parameters: } } ``` + +Return values: + ++ `200 Ok` on success and the updated merge request ++ `401 Unauthorize` if user is not authenticated or not allowed ++ `403 Forbidden` if user is not allowed to update the merge request ++ `404 Not Found` if project ID or merge request ID not found + + ## Post comment to MR -Post comment to MR +Adds a comment to a merge request. ``` POST /projects/:id/merge_request/:merge_request_id/comments @@ -183,10 +215,9 @@ POST /projects/:id/merge_request/:merge_request_id/comments Parameters: + `id` (required) - The ID of a project -+ `merge_request_id` (required) - ID of MR ++ `merge_request_id` (required) - ID of merge request + `note` (required) - Text of comment -Will return created note with status `201 Created` on success, or `404 Not found` on fail. ```json { @@ -201,3 +232,10 @@ Will return created note with status `201 Created` on success, or `404 Not found "note":"text1" } ``` + +Return values: + ++ `201 Created` on success and the new comment ++ `400 Bad Request` if the required attribute note is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or merge request ID not found diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 4b28094f..76cf8154 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -69,6 +69,10 @@ module Gitlab post ":id/merge_requests" do authorize! :write_merge_request, user_project + bad_request!(:source_branch) unless params[:source_branch].present? + bad_request!(:target_branch) unless params[:target_branch].present? + bad_request!(:title) unless params[:title].present? + attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title] merge_request = user_project.merge_requests.new(attrs) merge_request.author = current_user @@ -121,6 +125,8 @@ module Gitlab # POST /projects/:id/merge_request/:merge_request_id/comments # post ":id/merge_request/:merge_request_id/comments" do + bad_request!(:note) unless params[:note].present? + merge_request = user_project.merge_requests.find(params[:merge_request_id]) note = merge_request.notes.new(note: params[:note], project_id: user_project.id) note.author = current_user @@ -128,9 +134,6 @@ module Gitlab if note.save present note, with: Entities::MRNote else - if note.errors[:note].any? - bad_request!(:note) - end not_found! end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 8de06c33..e7af056a 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -64,6 +64,12 @@ describe Gitlab::API do title: "Test merge_request", source_branch: "stable", author: user response.status.should == 400 end + + it "should return 400 when title is missing" do + post api("/projects/#{project.id}/merge_requests", user), + target_branch: 'master', source_branch: 'stable' + response.status.should == 400 + end end describe "PUT /projects/:id/merge_request/:merge_request_id to close MR" do @@ -82,7 +88,6 @@ describe Gitlab::API do end end - describe "PUT /projects/:id/merge_request/:merge_request_id" do it "should return merge_request" do put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title" From 7499f65014257989510da50505fa7c0f5a4fae88 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 17:50:30 +0100 Subject: [PATCH 44/49] API: extracted helper method to validate required parameters, code clean up Added a helper method to check if required parameters are given in an API call. Can be used to return a `400 Bad Request` return code if a required attribute is missing. Code clean up and fixed tests. --- doc/api/projects.md | 3 ++- lib/api/groups.rb | 4 +--- lib/api/helpers.rb | 11 +++++++++++ lib/api/issues.rb | 2 +- lib/api/merge_requests.rb | 7 ++----- lib/api/milestones.rb | 3 +-- lib/api/notes.rb | 5 ++--- lib/api/projects.rb | 26 +++++++++----------------- lib/api/users.rb | 9 ++------- spec/requests/api/projects_spec.rb | 7 ++++--- 10 files changed, 35 insertions(+), 42 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 1d6afbc2..fe008096 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -368,7 +368,7 @@ Removes a hook from project. This is an idempotent method and can be called mult Either the hook is available or not. ``` -DELETE /projects/:id/hooks/:hook_id +DELETE /projects/:id/hooks/ ``` Parameters: @@ -379,6 +379,7 @@ Parameters: Return values: + `200 Ok` on succes ++ `403 Forbidden` if user is not allowed to delete a hook + `404 Not Found` if the project can not be found Note the JSON response differs if the hook is available or not. If the project hook diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 3f213073..5aaa5eb4 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -29,9 +29,7 @@ module Gitlab # POST /groups post do authenticated_as_admin! - - bad_request!(:name) unless params[:name].present? - bad_request!(:path) unless params[:path].present? + required_attributes! [:name, :path] attrs = attributes_for_keys [:name, :path] @group = Group.new(attrs) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index becb3bce..f12fb5fd 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -41,6 +41,17 @@ module Gitlab abilities.allowed?(object, action, subject) end + # Checks the occurrences of required attributes, each attribute must be present in the params hash + # or a Bad Request error is invoked. + # + # Parameters: + # keys (required) - A hash consisting of keys that must be present + def required_attributes!(keys) + keys.each do |key| + bad_request!(key) unless params[key].present? + end + end + def attributes_for_keys(keys) attrs = {} keys.each do |key| diff --git a/lib/api/issues.rb b/lib/api/issues.rb index da966fc0..500a8551 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -48,7 +48,7 @@ module Gitlab # Example Request: # POST /projects/:id/issues post ":id/issues" do - bad_request!(:title) unless params[:title].present? + required_attributes! [:title] attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id] attrs[:label_list] = params[:labels] if params[:labels].present? @issue = user_project.issues.new attrs diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 76cf8154..7e4ec7e8 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -68,10 +68,7 @@ module Gitlab # post ":id/merge_requests" do authorize! :write_merge_request, user_project - - bad_request!(:source_branch) unless params[:source_branch].present? - bad_request!(:target_branch) unless params[:target_branch].present? - bad_request!(:title) unless params[:title].present? + required_attributes! [:source_branch, :target_branch, :title] attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title] merge_request = user_project.merge_requests.new(attrs) @@ -125,7 +122,7 @@ module Gitlab # POST /projects/:id/merge_request/:merge_request_id/comments # post ":id/merge_request/:merge_request_id/comments" do - bad_request!(:note) unless params[:note].present? + required_attributes! [:note] merge_request = user_project.merge_requests.find(params[:merge_request_id]) note = merge_request.notes.new(note: params[:note], project_id: user_project.id) diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index ff98f005..1adeefec 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -41,8 +41,7 @@ module Gitlab # POST /projects/:id/milestones post ":id/milestones" do authorize! :admin_milestone, user_project - - bad_request!(:title) unless params[:title].present? + required_attributes! [:title] attrs = attributes_for_keys [:title, :description, :due_date] @milestone = user_project.milestones.new attrs diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 953514b6..759fd3a9 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -37,7 +37,7 @@ module Gitlab # Example Request: # POST /projects/:id/notes post ":id/notes" do - bad_request!(:body) unless params[:body].present? + required_attributes! [:body] @note = user_project.notes.new(note: params[:body]) @note.author = current_user @@ -93,8 +93,7 @@ module Gitlab # POST /projects/:id/issues/:noteable_id/notes # POST /projects/:id/snippets/:noteable_id/notes post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do - bad_request!(:"#{noteable_id_str}") unless params[:"#{noteable_id_str}"].present? - bad_request!(:body) unless params[:body].present? + required_attributes! [:"#{noteable_id_str}"] @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"]) @note = @noteable.notes.new(note: params[:body]) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index a1a7cee4..a65d6584 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -45,7 +45,7 @@ module Gitlab # Example Request # POST /projects post do - bad_request!(:name) if !params.has_key? :name + required_attributes! [:name] attrs = attributes_for_keys [:name, :description, :default_branch, @@ -103,9 +103,7 @@ module Gitlab # POST /projects/:id/members post ":id/members" do authorize! :admin_project, user_project - - bad_request!(:user_id) if !params.has_key? :user_id - bad_request!(:access_level) if !params.has_key? :access_level + required_attributes! [:user_id, :access_level] # either the user is already a team member or a new one team_member = user_project.team_member_by_id(params[:user_id]) @@ -134,9 +132,9 @@ module Gitlab # PUT /projects/:id/members/:user_id put ":id/members/:user_id" do authorize! :admin_project, user_project + required_attributes! [:access_level] team_member = user_project.users_projects.find_by_user_id(params[:user_id]) - bad_request!(:access_level) if !params.has_key? :access_level not_found!("User can not be found") if team_member.nil? if team_member.update_attributes(project_access: params[:access_level]) @@ -199,8 +197,7 @@ module Gitlab # POST /projects/:id/hooks post ":id/hooks" do authorize! :admin_project, user_project - - bad_request!(:url) unless params.has_key? :url + required_attributes! [:url] @hook = user_project.hooks.new({"url" => params[:url]}) if @hook.save @@ -224,8 +221,7 @@ module Gitlab put ":id/hooks/:hook_id" do @hook = user_project.hooks.find(params[:hook_id]) authorize! :admin_project, user_project - - bad_request!(:url) unless params.has_key? :url + required_attributes! [:url] attrs = attributes_for_keys [:url] if @hook.update_attributes attrs @@ -245,9 +241,9 @@ module Gitlab # hook_id (required) - The ID of hook to delete # Example Request: # DELETE /projects/:id/hooks/:hook_id - delete ":id/hooks/:hook_id" do + delete ":id/hooks" do authorize! :admin_project, user_project - bad_request!(:hook_id) unless params.has_key? :hook_id + required_attributes! [:hook_id] begin @hook = ProjectHook.find(params[:hook_id]) @@ -381,10 +377,7 @@ module Gitlab # POST /projects/:id/snippets post ":id/snippets" do authorize! :write_snippet, user_project - - bad_request!(:title) if !params[:title].present? - bad_request!(:file_name) if !params[:file_name].present? - bad_request!(:code) if !params[:code].present? + required_attributes! [:title, :file_name, :code] attrs = attributes_for_keys [:title, :file_name] attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? @@ -464,8 +457,7 @@ module Gitlab # GET /projects/:id/repository/commits/:sha/blob get ":id/repository/commits/:sha/blob" do authorize! :download_code, user_project - - bad_request!(:filepath) if !params.has_key? :filepath + required_attributes! [:filepath] ref = params[:sha] diff --git a/lib/api/users.rb b/lib/api/users.rb index b9dce58a..5e0680de 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -41,11 +41,7 @@ module Gitlab # POST /users post do authenticated_as_admin! - - bad_request!(:email) if !params.has_key? :email - bad_request!(:password) if !params.has_key? :password - bad_request!(:name) if !params.has_key? :name - bad_request!(:username) if !params.has_key? :username + required_attributes! [:email, :password, :name, :username] attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] user = User.new attrs, as: :admin @@ -135,8 +131,7 @@ module Gitlab # Example Request: # POST /user/keys post "keys" do - bad_request!(:title) unless params[:title].present? - bad_request!(:key) unless params[:key].present? + required_attributes! [:title, :key] attrs = attributes_for_keys [:title, :key] key = current_user.keys.new attrs diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 9fbdd52e..71a33f85 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -424,10 +424,10 @@ describe Gitlab::API do end end - describe "DELETE /projects/:id/hooks/:hook_id" do + describe "DELETE /projects/:id/hooks" do it "should delete hook from project" do expect { - delete api("/projects/#{project.id}/hooks/#{hook.id}", user) + delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id }.to change {project.hooks.count}.by(-1) response.status.should == 200 end @@ -466,7 +466,8 @@ describe Gitlab::API do response.status.should == 200 json_response.should be_an Array - json_response.first['id'].should == project.repository.commit.id + #json_response.first['id'].should == project.repository.commit.id + json_response.size.should == 1 end end From d269d107d86c600ab2add651f47cced8f601ae84 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 18:12:02 +0100 Subject: [PATCH 45/49] API: fixed adding a note Now the correct attribute is checked if it's available or not. Also fixed a test. --- lib/api/notes.rb | 2 +- spec/requests/api/projects_spec.rb | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 759fd3a9..097cc7ea 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -93,7 +93,7 @@ module Gitlab # POST /projects/:id/issues/:noteable_id/notes # POST /projects/:id/snippets/:noteable_id/notes post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do - required_attributes! [:"#{noteable_id_str}"] + required_attributes! [:body] @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"]) @note = @noteable.notes.new(note: params[:body]) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 71a33f85..994c8d5e 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -466,8 +466,7 @@ describe Gitlab::API do response.status.should == 200 json_response.should be_an Array - #json_response.first['id'].should == project.repository.commit.id - json_response.size.should == 1 + json_response.first['id'].should == project.repository.commit.id end end From cce35b6d057611d792bdc70022bd7264798527a7 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 5 Mar 2013 22:33:45 +0100 Subject: [PATCH 46/49] Fixes api --- lib/api/projects.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 6df00db7..cf48f88b 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -52,8 +52,7 @@ module Gitlab :issues_enabled, :wall_enabled, :merge_requests_enabled, - :wiki_enabled, - :namespace_id] + :wiki_enabled] @project = ::Projects::CreateContext.new(current_user, attrs).execute if @project.saved? present @project, with: Entities::Project From b5ef6d226864d3ea132d2c6e97b74b51f2b64a6f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 5 Mar 2013 23:43:05 +0100 Subject: [PATCH 47/49] API: refactored and simplified error handling in merge requests API --- lib/api/merge_requests.rb | 23 ++++++----------------- lib/api/projects.rb | 3 ++- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 7e4ec7e8..5adf57b3 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -4,21 +4,12 @@ module Gitlab before { authenticate! } resource :projects do - helpers do - # If an error occurred this helper method provides an appropriate status code - # - # Parameters: - # merge_request_errors (required) - The errors collection of MR - # - def handle_merge_request_error(merge_request_errors) - if merge_request_errors[:target_branch].any? - bad_request!(:target_branch) - elsif merge_request_errors[:source_branch].any? - bad_request!(:source_branch) - elsif merge_request_errors[:base].any? - error!(merge_request_errors[:base], 422) + def handle_merge_request_errors!(errors) + if errors[:project_access].any? + error!(errors[:project_access], 422) end + not_found! end end @@ -78,8 +69,7 @@ module Gitlab merge_request.reload_code present merge_request, with: Entities::MergeRequest else - handle_merge_request_error(merge_request.errors) - not_found! + handle_merge_request_errors! merge_request.errors end end @@ -107,8 +97,7 @@ module Gitlab merge_request.mark_as_unchecked present merge_request, with: Entities::MergeRequest else - handle_merge_request_error(merge_request.errors) - not_found! + handle_merge_request_errors! merge_request.errors end end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index cf48f88b..b8efef31 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -233,7 +233,7 @@ module Gitlab end end - # Delete project hook + # Deletes project hook. This is an idempotent function. # # Parameters: # id (required) - The ID of a project @@ -248,6 +248,7 @@ module Gitlab @hook = ProjectHook.find(params[:hook_id]) @hook.destroy rescue + # ProjectHook can raise Error if hook_id not found end end From 39114d259c6e4bd5bb60b18f561d06cc24e8c852 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 7 Mar 2013 00:15:57 +0100 Subject: [PATCH 48/49] API: documentation contains infos to status codes in README file. All the info to return codes from the API functions are available in the `README.md` file as suggested. --- doc/api/README.md | 36 +++++++++++ doc/api/groups.md | 19 ------ doc/api/issues.md | 35 ---------- doc/api/merge_requests.md | 34 ---------- doc/api/milestones.md | 24 ------- doc/api/notes.md | 78 ---------------------- doc/api/projects.md | 133 -------------------------------------- doc/api/repositories.md | 47 -------------- doc/api/session.md | 5 -- doc/api/snippets.md | 36 ----------- doc/api/users.md | 64 ------------------ 11 files changed, 36 insertions(+), 475 deletions(-) diff --git a/doc/api/README.md b/doc/api/README.md index 5a662cec..2699434d 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -27,6 +27,42 @@ curl --header "PRIVATE-TOKEN: QVy1PB7sTxfy4pqfZM1U" "http://example.com/api/v3/p The API uses JSON to serialize data. You don't need to specify `.json` at the end of API URL. + + +## Status codes + +API requests return different status codes according to + +The API is designed to provide status codes according to the context and how the request +is handled. For example if a `GET` request is successful a status code `200 Ok` +is returned. The API is designed to be RESTful. + +The following list gives an overview of how the API functions are designed. + +API request types: + +* `GET` requests access one or more resources and return the result as JSON +* `POST` requests return `201 Created` if the resource is successfully created and return the newly created resource as JSON +* `GET`, `PUT` and `DELETE` return `200 Ok` if the resource is accessed, modified or deleted successfully, the (modified) result is returned as JSON +* `DELETE` requests are designed to be idempotent, meaning a request a resource still returns `200 Ok` even it was deleted before or is not available. The reasoning behind it is the user is not really interested if the resource existed before or not. + + +The following list shows the possible return codes for API requests. + +Return values: + +* `200 Ok` - The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON +* `201 Created` - The `POST` request was successful and the resource is returned as JSON +* `400 Bad Request` - A required attribute of the API request is missing, e.g. the title of an issue is not given +* `401 Unauthorized` - The user is not authenticated, a valid user token is necessary, see above +* `403 Forbidden` - The request is not allowed, e.g. the user is not allowed to delete a project +* `404 Not Found` - A resource could not be accessed, e.g. an ID for a resource could not be found +* `405 Method Not Allowed` - The request is not supported +* `409 Conflict` - A conflicting resource already exists, a project with same name already exists +* `500 Server Error` - While handling the request something went wrong on the server side + + + #### Pagination When listing resources you can pass the following parameters: diff --git a/doc/api/groups.md b/doc/api/groups.md index c97851a5..25b9741f 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -17,12 +17,6 @@ GET /groups ] ``` -Return values: - -+ `200 Ok` on success and list of groups -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if something fails - ## Details of a group @@ -36,12 +30,6 @@ Parameters: + `id` (required) - The ID of a group -Return values: - -+ `200 Ok` on success and the details of a group -+ `401 Unauthorized` if user not authenticated -+ `404 Not Found` if group ID not found - ## New group @@ -56,10 +44,3 @@ Parameters: + `name` (required) - The name of the group + `path` (required) - The path of the group -Return valueS: - -+ `201 Created` on success and the newly created group -+ `400 Bad Request` if one of the required attributes not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if something fails - diff --git a/doc/api/issues.md b/doc/api/issues.md index 025c6e50..a8ae7401 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -69,13 +69,6 @@ GET /issues ] ``` -Return values: - -+ `200 Ok` on success and the list of issues -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if something fails - - ## List project issues @@ -90,12 +83,6 @@ Parameters: + `id` (required) - The ID of a project -Return values: - -+ `200 Ok` on success and the list of project issues -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Single issue @@ -150,12 +137,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the list of project issues -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or issue ID not found - ## New issue @@ -174,13 +155,6 @@ Parameters: + `milestone_id` (optional) - The ID of a milestone to assign issue + `labels` (optional) - Comma-separated label names for an issue -Return values: - -+ `201 Created` on success and the newly created project issue -+ `400 Bad Request` if the required attribute title is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Edit issue @@ -201,12 +175,6 @@ Parameters: + `labels` (optional) - Comma-separated label names for an issue + `closed` (optional) - The state of an issue (0 = false, 1 = true) -Return values: - -+ `200 Ok` on success and the update project issue -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or issue ID not found - ## Delete existing issue (**Deprecated**) @@ -223,6 +191,3 @@ Parameters: + `id` (required) - The project ID + `issue_id` (required) - The ID of the issue -Return values: - -+ `405 Method Not Allowed` is always returned, because the function is deprecated diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 633aca78..111c5211 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -41,12 +41,6 @@ Parameters: ] ``` -Return values: - -+ `200 Ok` on success and the list of merge requests -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Get single MR @@ -89,12 +83,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the single merge request -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or merge request ID not found - ## Create MR @@ -140,14 +128,6 @@ Parameters: } ``` -Return values: - -+ `201 Created` on success and the created merge request -+ `400 Bad Request` if one of the required attributes is missing -+ `401 Unauthorize` if user is not authenticated or not allowed -+ `403 Forbidden` if user is not allowed to create a merge request -+ `404 Not Found` if project ID not found or something else fails - ## Update MR @@ -196,13 +176,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the updated merge request -+ `401 Unauthorize` if user is not authenticated or not allowed -+ `403 Forbidden` if user is not allowed to update the merge request -+ `404 Not Found` if project ID or merge request ID not found - ## Post comment to MR @@ -232,10 +205,3 @@ Parameters: "note":"text1" } ``` - -Return values: - -+ `201 Created` on success and the new comment -+ `400 Bad Request` if the required attribute note is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or merge request ID not found diff --git a/doc/api/milestones.md b/doc/api/milestones.md index 9bb27271..92a29cee 100644 --- a/doc/api/milestones.md +++ b/doc/api/milestones.md @@ -10,12 +10,6 @@ Parameters: + `id` (required) - The ID of a project -Return values: - -+ `200 Ok` on success and the list of project milestones -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Get single milestone @@ -30,12 +24,6 @@ Parameters: + `id` (required) - The ID of a project + `milestone_id` (required) - The ID of a project milestone -Return values: - -+ `200 Ok` on success and the single milestone -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Create new milestone @@ -52,13 +40,6 @@ Parameters: + `description` (optional) - The description of the milestone + `due_date` (optional) - The due date of the milestone -Return values: - -+ `201 Created` on success and the new milestone -+ `400 Bad Request` if the required attribute title is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Edit milestone @@ -77,8 +58,3 @@ Parameters: + `due_date` (optional) - The due date of the milestone + `closed` (optional) - The status of the milestone -Return values: - -+ `200 Ok` on success and the updated milestone -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or milestone ID not found diff --git a/doc/api/notes.md b/doc/api/notes.md index 6a6a99aa..4b57f636 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -30,11 +30,6 @@ Parameters: + `id` (required) - The ID of a project -Return values: - -+ `200 Ok` on success and a list of notes -+ `401 Unauthorized` if user is not authorized to access this page - ### Get single wall note @@ -49,12 +44,6 @@ Parameters: + `id` (required) - The ID of a project + `note_id` (required) - The ID of a wall note -Return values: - -+ `200 Ok` on success and the wall note (see example at `GET /projects/:id/notes`) -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if note ID not found - ### Create new wall note @@ -69,14 +58,6 @@ Parameters: + `id` (required) - The ID of a project + `body` (required) - The content of a note -Return values: - -+ `201 Created` on success and the new wall note -+ `400 Bad Request` if attribute body is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if something else fails - - ## Issues @@ -93,12 +74,6 @@ Parameters: + `id` (required) - The ID of a project + `issue_id` (required) - The ID of an issue -Return values: - -+ `200 Ok` on success and a list of notes for a single issue -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or issue ID not found - ### Get single issue note @@ -114,12 +89,6 @@ Parameters: + `issue_id` (required) - The ID of a project issue + `note_id` (required) - The ID of an issue note -Return values: - -+ `200 Ok` on success and the single issue note -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID, issue ID or note ID is not found - ### Create new issue note @@ -135,14 +104,6 @@ Parameters: + `issue_id` (required) - The ID of an issue + `body` (required) - The content of a note -Return values: - -+ `201 Created` on succes and the created note -+ `400 Bad Request` if the required attribute body is not given -+ `401 Unauthorized` if the user is not authenticated -+ `404 Not Found` if the project ID or the issue ID not found - - ## Snippets @@ -159,12 +120,6 @@ Parameters: + `id` (required) - The ID of a project + `snippet_id` (required) - The ID of a project snippet -Return values: - -+ `200 Ok` on success and a list of notes for a single snippet -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or issue ID not found - ### Get single snippet note @@ -180,12 +135,6 @@ Parameters: + `snippet_id` (required) - The ID of a project snippet + `note_id` (required) - The ID of an snippet note -Return values: - -+ `200 Ok` on success and the single snippet note -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID, snippet ID or note ID is not found - ### Create new snippet note @@ -201,14 +150,6 @@ Parameters: + `snippet_id` (required) - The ID of an snippet + `body` (required) - The content of a note -Return values: - -+ `201 Created` on success and the new snippet note -+ `400 Bad Request` if the required attribute body not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or snippet ID not found - - ## Merge Requests @@ -225,12 +166,6 @@ Parameters: + `id` (required) - The ID of a project + `merge_request_id` (required) - The ID of a project merge request -Return values: - -+ `200 Ok` on success and a list of notes for a single merge request -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or merge request ID not found - ### Get single merge request note @@ -246,12 +181,6 @@ Parameters: + `merge_request_id` (required) - The ID of a project merge request + `note_id` (required) - The ID of a merge request note -Return values: - -+ `200 Ok` on success and the single merge request note -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID, merge request ID or note ID is not found - ### Create new merge request note @@ -267,10 +196,3 @@ Parameters: + `merge_request_id` (required) - The ID of a merge request + `body` (required) - The content of a note -Return values: - -+ `201 Created` on success and the new merge request note -+ `400 Bad Request` if the required attribute body not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or merge request ID not found - diff --git a/doc/api/projects.md b/doc/api/projects.md index fe008096..326a62b0 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -57,11 +57,6 @@ GET /projects ] ``` -Return values: - -+ `200 Ok` on success and a list of projects -+ `401 Unauthorized` if the user is not allowed to access projects - ### Get single project @@ -101,11 +96,6 @@ Parameters: } ``` -Return Values: - -+ `200 Ok` if the project with given ID is found and the JSON response -+ `404 Not Found` if no project with ID found - ### Create project @@ -125,13 +115,6 @@ Parameters: + `merge_requests_enabled` (optional) - enabled by default + `wiki_enabled` (optional) - enabled by default -Return values: - -+ `201 Created` on success with the project data (see example at `GET /projects/:id`) -+ `400 Bad Request` if the required attribute name is not given -+ `403 Forbidden` if the user is not allowed to create a project, e.g. reached the project limit already -+ `404 Not Found` if something else fails - ## Project access levels @@ -159,11 +142,6 @@ Parameters: + `id` (required) - The ID or NAME of a project + `query` - Query string -Return Values: - -+ `200 Ok` on success and a list of found team members -+ `404 Not Found` if project with ID not found - ## Team members @@ -192,11 +170,6 @@ Parameters: } ``` -Return Values: - -+ `200 Ok` on success and the team member, see example -+ `404 Not Found` if either the project or the team member could not be found - ### Add project team member @@ -214,14 +187,6 @@ Parameters: + `user_id` (required) - The ID of a user to add + `access_level` (required) - Project access level -Return Values: - -+ `201 Created` on success and the added user is returned, even if the user is already team member -+ `400 Bad Request` if the required attribute access_level is not given -+ `401 Unauthorized` if the user is not allowed to add a new team member -+ `404 Not Found` if a resource can not be found, e.g. project with ID not available -+ `422 Unprocessable Entity` if an unknown access_level is given - ### Edit project team member @@ -237,14 +202,6 @@ Parameters: + `user_id` (required) - The ID of a team member + `access_level` (required) - Project access level -Return Values: - -+ `200 Ok` on succes and the modified team member -+ `400 Bad Request` if the required attribute access_level is not given -+ `401 Unauthorized` if the user is not allowed to modify a team member -+ `404 Not Found` if a resource can not be found, e.g. project with ID not available -+ `422 Unprocessable Entity` if an unknown access_level is given - ### Remove project team member @@ -259,12 +216,6 @@ Parameters: + `id` (required) - The ID or NAME of a project + `user_id` (required) - The ID of a team member -Return Values: - -+ `200 Ok` on success -+ `401 Unauthorized` if user is not allowed to remove a team member -+ `404 Not Found` if either project or user can not be found - This method is idempotent and can be called multiple times with the same parameters. Revoking team membership for a user who is not currently a team member is considered success. Please note that the returned JSON currently differs slightly. Thus you should not @@ -285,12 +236,6 @@ Parameters: + `id` (required) - The ID or NAME of a project -Return values: - -+ `200 Ok` on success with a list of hooks -+ `401 Unauthorized` if user is not allowed to get list of hooks -+ `404 Not Found` if project can not be found - ### Get project hook @@ -313,11 +258,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on sucess and the hook with the given ID -+ `404 Not Found` if the hook can not be found - ### Add project hook @@ -332,13 +272,6 @@ Parameters: + `id` (required) - The ID or NAME of a project + `url` (required) - The hook URL -Return values: - -+ `201 Created` on success and the newly created hook -+ `400 Bad Request` if url is not given -+ `404 Not Found` if project with ID not found -+ `422 Unprocessable Entity` if the url is invalid (must begin with `http` or `https`) - ### Edit project hook @@ -354,13 +287,6 @@ Parameters: + `hook_id` (required) - The ID of a project hook + `url` (required) - The hook URL -Return values: - -+ `200 Ok` on success and the modified hook (see JSON response above) -+ `400 Bad Request` if the url attribute is not given -+ `404 Not Found` if project or hook can not be found -+ `422 Unprocessable Entity` if the url is invalid (must begin with `http` or `https`) - ### Delete project hook @@ -376,12 +302,6 @@ Parameters: + `id` (required) - The ID or NAME of a project + `hook_id` (required) - The ID of hook to delete -Return values: - -+ `200 Ok` on succes -+ `403 Forbidden` if user is not allowed to delete a hook -+ `404 Not Found` if the project can not be found - Note the JSON response differs if the hook is available or not. If the project hook is available before it is returned in the JSON response or an empty response is returned. @@ -400,11 +320,6 @@ Parameters: + `id` (required) - The ID of the project -Return values: - -+ `200 Ok` on success and a list of branches -+ `404 Not Found` if project is not found - ### List single branch @@ -419,11 +334,6 @@ Parameters: + `id` (required) - The ID of the project. + `branch` (required) - The name of the branch. -Return values: - -+ `200 Ok` on success -+ `404 Not Found` if either project with ID or branch could not be found - ### Protect single branch @@ -438,11 +348,6 @@ Parameters: + `id` (required) - The ID of the project. + `branch` (required) - The name of the branch. -Return values: - -+ `200 Ok` on success -+ `404 Not Found` if either project or branch could not be found - ### Unprotect single branch @@ -457,11 +362,6 @@ Parameters: + `id` (required) - The ID of the project. + `branch` (required) - The name of the branch. -Return values: - -+ `200 Ok` on success -+ `404 Not Found` if either project or branch could not be found - ### List tags @@ -475,11 +375,6 @@ Parameters: + `id` (required) - The ID of the project -Return values: - -+ `200 Ok` on success and a list of tags -+ `404 Not Found` if project with id not found - ### List commits @@ -517,11 +412,6 @@ Parameters: + `id` (required) - The ID of the project -Return values: - -+ `200 Ok` on success and the list of snippets -+ `404 Not Found` if project with id not found - ### List single snippet @@ -536,11 +426,6 @@ Parameters: + `id` (required) - The ID of the project + `snippet_id` (required) - The ID of the snippet -Return values: - -+ `200 Ok` on success and the project snippet -+ `404 Not Found` if project ID or snippet ID not found - ### Create snippet @@ -558,13 +443,6 @@ Parameters: + `code` (required) - The content of the snippet + `lifetime` (optional) - The expiration date of a snippet -Return values: - -+ `201 Created` on success and the new snippet -+ `400 Bad Request` if one of the required attributes is missing -+ `401 Unauthorized` if it is not allowed to post a new snippet -+ `404 Not Found` if the project ID is not found - ### Update snippet @@ -583,12 +461,6 @@ Parameters: + `lifetime` (optional) - The new expiration date of the snippet + `code` (optional) - The content of the snippet -Return values: - -+ `200 Ok` on success and the content of the updated snippet -+ `401 Unauthorized` if the user is not allowed to modify the snippet -+ `404 Not Found` if project ID or snippet ID is not found - ## Delete snippet @@ -604,8 +476,3 @@ Paramaters: + `id` (required) - The ID of the project + `snippet_id` (required) - The ID of the snippet -Return values: - -+ `200 Ok` on success, if the snippet got deleted it is returned, if not available then an empty JSON response -+ `401 Unauthorized` if the user is not allowed to remove the snippet -+ `404 Not Found` if the project ID not found diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 17346278..39a7b0ed 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -39,12 +39,6 @@ Parameters: ] ``` -Return values: - -+ `200 Ok`on success and a list of repository branches for the project -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project with ID not found - ## Get single repository branch @@ -86,13 +80,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the repository branch -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if the project ID or branch not found - - ## Protect repository branch @@ -135,13 +122,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the updated repository branch -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if the the project ID or branch not found - - ## Unprotect repository branch @@ -184,13 +164,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the updated repository branch -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if the project ID or the branch not found - - ## List project repository tags @@ -231,12 +204,6 @@ Parameters: ] ``` -Return values: - -+ `200 Ok` on success and the list of repository tags -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if the project ID not found - ## List repository commits @@ -274,12 +241,6 @@ Parameters: ] ``` -Return values: - -+ `200 Ok` on success and a list of commits -+ `401 Unauthorized` if the user is not authenticated -+ `404 Not Found` if the project ID not found - ## Raw blob content @@ -294,11 +255,3 @@ Parameters: + `id` (required) - The ID of a project + `sha` (required) - The commit or branch name + `filepath` (required) - The path the file - -Return values: - -+ `200 Ok` on success and the raw content of the file -+ `400 Bad Request` if required attribute filepath is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or sha commit or branch name not found - diff --git a/doc/api/session.md b/doc/api/session.md index 5f49d989..c7e57aac 100644 --- a/doc/api/session.md +++ b/doc/api/session.md @@ -21,8 +21,3 @@ Parameters: "blocked": true } ``` - -Return values: - -+ `201 Created` on success -+ `401 Unauthorized` if the authentication process failed, e.g. invalid password or attribute not given diff --git a/doc/api/snippets.md b/doc/api/snippets.md index 61dbb5e4..4becc928 100644 --- a/doc/api/snippets.md +++ b/doc/api/snippets.md @@ -10,11 +10,6 @@ Parameters: + `id` (required) - The ID of a project -Return values: - -+ `200 Ok` on success and a list of project snippets -+ `401 Unauthorized` if user is not authenticated - ## Single snippet @@ -48,12 +43,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the project snippet -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if snippet ID not found - ## Create new snippet @@ -71,13 +60,6 @@ Parameters: + `lifetime` (optional) - The expiration date of a snippet + `code` (required) - The content of a snippet -Return values: - -+ `201 Created` if snippet was successfully created and the snippet as JSON payload -+ `400 Bad Request` if one of the required attributes is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Edit snippet @@ -96,12 +78,6 @@ Parameters: + `lifetime` (optional) - The expiration date of a snippet + `code` (optional) - The content of a snippet -Return values: - -+ `200 Ok` on success and the updated project snippet -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Delete snippet @@ -117,12 +93,6 @@ Parameters: + `id` (required) - The ID of a project + `snippet_id` (required) - The ID of a project's snippet -Return values: - -+ `200 Ok` on success and if the snippet was deleted its content -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Snippet content @@ -136,9 +106,3 @@ Parameters: + `id` (required) - The ID of a project + `snippet_id` (required) - The ID of a project's snippet - -Return values: - -+ `200 Ok` on success and the raw snippet -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or snippet ID is not found \ No newline at end of file diff --git a/doc/api/users.md b/doc/api/users.md index 96aebffa..6d5c9d78 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -43,11 +43,6 @@ GET /users ] ``` -Return values: - -+ `200 Ok` on success and a list with all users -+ `401 Unauthorized` if user is not allowed to access the list - ## Single user @@ -80,12 +75,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the user entry -+ `401 Unauthorized` if it is not allowed to access the user -+ `404 Not Found` if the user with ID is not found - ## User creation @@ -109,15 +98,6 @@ Parameters: + `provider` (optional) - External provider name + `bio` (optional) - User's bio -Return values: - -+ `201 Created` on success and returns the new user -+ `400 Bad Request` if one of the required attributes is missing from the request -+ `401 Unauthorized` if the user is not authorized -+ `403 Forbidden` if the user is not allowed to create a new user (must be admin) -+ `404 Not Found` if something else fails -+ `409 Conflict` if a user with the same email address or username already exists - ## User modification @@ -141,13 +121,6 @@ Parameters: + `provider` - External provider name + `bio` - User's bio -Return values: - -+ `200 Ok` on success and returns the new user -+ `401 Unauthorized` if the user is not authorized -+ `403 Forbidden` if the user is not allowed to create a new user (must be admin) -+ `404 Not Found` if something else fails - Note, at the moment this method does only return a 404 error, even in cases where a 409 (Conflict) would be more appropriate, e.g. when renaming the email address to some exsisting one. @@ -166,13 +139,6 @@ Parameters: + `id` (required) - The ID of the user -Return values: - -+ `200 Ok` on success and returns the deleted user -+ `401 Unauthorized` if the user is not authorized -+ `403 Forbidden` if the user is not allowed to create a new user (must be admin) -+ `404 Not Found` if user with ID not found or something else fails - ## Current user @@ -199,12 +165,6 @@ GET /user } ``` -Return values: - -+ `200 Ok` on success and returns the current user -+ `401 Unauthorized` if the user is not authorized -+ `404 Not Found` if something else fails - ## List SSH keys @@ -237,12 +197,6 @@ Parameters: + **none** -Return values: - -+ `200 Ok` on success and a list of ssh keys -+ `401 Unauthorized` if the user is not authenticated -+ `404 Not Found` if something else fails - ## Single SSH key @@ -266,12 +220,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the ssh key with ID -+ `401 Unauthorized` if it is not allowed to access the user -+ `404 Not Found` if the ssh key with ID not found - ## Add SSH key @@ -286,13 +234,6 @@ Parameters: + `title` (required) - new SSH Key's title + `key` (required) - new SSH key -Return values: - -+ `201 Created` on success and the added key -+ `400 Bad Request` if one of the required attributes is not given -+ `401 Unauthorized` if user is not authorized to add ssh key -+ `404 Not Found` if something else fails - ## Delete SSH key @@ -307,8 +248,3 @@ Parameters: + `id` (required) - SSH key ID -Return values: - -+ `200 Ok` on success -+ `401 Unauthorized` if user is not allowed to delete they key -+ `404 Not Found` if something else fails From ecf53bb9e616b724bafc939d5e74744e774e3fd2 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 7 Mar 2013 15:11:33 +0100 Subject: [PATCH 49/49] API: fixes project creation and removed redundant info --- doc/api/repositories.md | 2 -- lib/api/groups.rb | 3 --- lib/api/projects.rb | 6 +++--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 39a7b0ed..90fda387 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -217,8 +217,6 @@ Parameters: + `id` (required) - The ID of a project + `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch -+ `page`(optional) - The page with the commits (pagination) -+ `per_page` (optional) - The number of commits per page (pagination) ```json [ diff --git a/lib/api/groups.rb b/lib/api/groups.rb index beb61519..52fa8eff 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -6,9 +6,6 @@ module Gitlab resource :groups do # Get a groups list # - # Parameters - # page (optional) - The page number of the groups list - # per_page (optional) - The number of elements per page # Example Request: # GET /groups get do diff --git a/lib/api/projects.rb b/lib/api/projects.rb index b1d6357f..e82cfeca 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -42,6 +42,7 @@ module Gitlab # wall_enabled (optional) - enabled by default # merge_requests_enabled (optional) - enabled by default # wiki_enabled (optional) - enabled by default + # namespace_id (optional) - defaults to user namespace # Example Request # POST /projects post do @@ -52,7 +53,8 @@ module Gitlab :issues_enabled, :wall_enabled, :merge_requests_enabled, - :wiki_enabled] + :wiki_enabled, + :namespace_id] @project = ::Projects::CreateContext.new(current_user, attrs).execute if @project.saved? present @project, with: Entities::Project @@ -360,8 +362,6 @@ module Gitlab # Parameters: # id (required) - The ID of a project # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used - # page (optional) - The page number of the commit pagination - # per_page (optional) - The number of elements per page used in pagination # Example Request: # GET /projects/:id/repository/commits get ":id/repository/commits" do