Commit 318350e34fcd0b0754526fdfb94c484b8bb88837
Exists in
master
and in
4 other branches
Merge branch 'api' of https://github.com/NARKOZ/gitlabhq
Conflicts: Gemfile.lock
Showing
9 changed files
with
206 additions
and
0 deletions
Show diff stats
Gemfile
| @@ -18,6 +18,7 @@ gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git" | @@ -18,6 +18,7 @@ gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git" | ||
| 18 | gem 'grack', :git => "https://github.com/gitlabhq/grack.git" | 18 | gem 'grack', :git => "https://github.com/gitlabhq/grack.git" |
| 19 | gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git" | 19 | gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git" |
| 20 | 20 | ||
| 21 | +gem "grape" | ||
| 21 | gem "stamp" | 22 | gem "stamp" |
| 22 | gem "kaminari" | 23 | gem "kaminari" |
| 23 | gem "haml-rails" | 24 | gem "haml-rails" |
Gemfile.lock
| @@ -169,6 +169,12 @@ GEM | @@ -169,6 +169,12 @@ GEM | ||
| 169 | gherkin (2.11.0) | 169 | gherkin (2.11.0) |
| 170 | json (>= 1.4.6) | 170 | json (>= 1.4.6) |
| 171 | git (1.2.5) | 171 | git (1.2.5) |
| 172 | + grape (0.2.0) | ||
| 173 | + hashie (~> 1.2) | ||
| 174 | + multi_json | ||
| 175 | + multi_xml | ||
| 176 | + rack | ||
| 177 | + rack-mount | ||
| 172 | haml (3.1.6) | 178 | haml (3.1.6) |
| 173 | haml-rails (0.3.4) | 179 | haml-rails (0.3.4) |
| 174 | actionpack (~> 3.0) | 180 | actionpack (~> 3.0) |
| @@ -230,6 +236,8 @@ GEM | @@ -230,6 +236,8 @@ GEM | ||
| 230 | rack (1.4.1) | 236 | rack (1.4.1) |
| 231 | rack-cache (1.2) | 237 | rack-cache (1.2) |
| 232 | rack (>= 0.4) | 238 | rack (>= 0.4) |
| 239 | + rack-mount (0.8.3) | ||
| 240 | + rack (>= 1.0.0) | ||
| 233 | rack-protection (1.2.0) | 241 | rack-protection (1.2.0) |
| 234 | rack | 242 | rack |
| 235 | rack-ssl (1.3.2) | 243 | rack-ssl (1.3.2) |
| @@ -381,6 +389,7 @@ DEPENDENCIES | @@ -381,6 +389,7 @@ DEPENDENCIES | ||
| 381 | git | 389 | git |
| 382 | gitolite! | 390 | gitolite! |
| 383 | grack! | 391 | grack! |
| 392 | + grape | ||
| 384 | grit! | 393 | grit! |
| 385 | haml-rails | 394 | haml-rails |
| 386 | httparty | 395 | httparty |
config/routes.rb
| @@ -4,6 +4,10 @@ Gitlab::Application.routes.draw do | @@ -4,6 +4,10 @@ Gitlab::Application.routes.draw do | ||
| 4 | # | 4 | # |
| 5 | get 'search' => "search#show" | 5 | get 'search' => "search#show" |
| 6 | 6 | ||
| 7 | + # API | ||
| 8 | + require 'api' | ||
| 9 | + mount Gitlab::API => '/api' | ||
| 10 | + | ||
| 7 | # Optionally, enable Resque here | 11 | # Optionally, enable Resque here |
| 8 | require 'resque/server' | 12 | require 'resque/server' |
| 9 | mount Resque::Server.new, at: '/info/resque' | 13 | mount Resque::Server.new, at: '/info/resque' |
| @@ -0,0 +1,61 @@ | @@ -0,0 +1,61 @@ | ||
| 1 | +require 'api/entities' | ||
| 2 | +require 'api/helpers' | ||
| 3 | + | ||
| 4 | +module Gitlab | ||
| 5 | + class API < Grape::API | ||
| 6 | + format :json | ||
| 7 | + helpers APIHelpers | ||
| 8 | + | ||
| 9 | + # Users API | ||
| 10 | + resource :users do | ||
| 11 | + before { authenticate! } | ||
| 12 | + | ||
| 13 | + # GET /users | ||
| 14 | + get do | ||
| 15 | + @users = User.all | ||
| 16 | + present @users, :with => Entities::User | ||
| 17 | + end | ||
| 18 | + | ||
| 19 | + # GET /users/:id | ||
| 20 | + get ":id" do | ||
| 21 | + @user = User.find(params[:id]) | ||
| 22 | + present @user, :with => Entities::User | ||
| 23 | + end | ||
| 24 | + end | ||
| 25 | + | ||
| 26 | + # GET /user | ||
| 27 | + get "/user" do | ||
| 28 | + authenticate! | ||
| 29 | + present @current_user, :with => Entities::User | ||
| 30 | + end | ||
| 31 | + | ||
| 32 | + # Projects API | ||
| 33 | + resource :projects do | ||
| 34 | + before { authenticate! } | ||
| 35 | + | ||
| 36 | + # GET /projects | ||
| 37 | + get do | ||
| 38 | + @projects = current_user.projects | ||
| 39 | + present @projects, :with => Entities::Project | ||
| 40 | + end | ||
| 41 | + | ||
| 42 | + # GET /projects/:id | ||
| 43 | + get ":id" do | ||
| 44 | + @project = current_user.projects.find_by_code(params[:id]) | ||
| 45 | + present @project, :with => Entities::Project | ||
| 46 | + end | ||
| 47 | + | ||
| 48 | + # GET /projects/:id/repository/branches | ||
| 49 | + get ":id/repository/branches" do | ||
| 50 | + @project = current_user.projects.find_by_code(params[:id]) | ||
| 51 | + present @project.repo.heads.sort_by(&:name), :with => Entities::ProjectRepositoryBranches | ||
| 52 | + end | ||
| 53 | + | ||
| 54 | + # GET /projects/:id/repository/tags | ||
| 55 | + get ":id/repository/tags" do | ||
| 56 | + @project = current_user.projects.find_by_code(params[:id]) | ||
| 57 | + present @project.repo.tags.sort_by(&:name).reverse, :with => Entities::ProjectRepositoryTags | ||
| 58 | + end | ||
| 59 | + end | ||
| 60 | + end | ||
| 61 | +end |
| @@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
| 1 | +module Gitlab | ||
| 2 | + module Entities | ||
| 3 | + class User < Grape::Entity | ||
| 4 | + expose :id, :email, :name, :bio, :skype, :linkedin, :twitter, | ||
| 5 | + :dark_scheme, :theme_id, :blocked, :created_at | ||
| 6 | + end | ||
| 7 | + | ||
| 8 | + class Project < Grape::Entity | ||
| 9 | + expose :id, :code, :name, :description, :path, :default_branch | ||
| 10 | + expose :owner, :using => Entities::User | ||
| 11 | + expose :private_flag, :as => :private | ||
| 12 | + expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at | ||
| 13 | + end | ||
| 14 | + | ||
| 15 | + class ProjectRepositoryBranches < Grape::Entity | ||
| 16 | + expose :name, :commit | ||
| 17 | + end | ||
| 18 | + | ||
| 19 | + class ProjectRepositoryTags < Grape::Entity | ||
| 20 | + expose :name, :commit | ||
| 21 | + end | ||
| 22 | + end | ||
| 23 | +end |
| @@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe Gitlab::API do | ||
| 4 | + let(:user) { Factory :user } | ||
| 5 | + let!(:project) { Factory :project, :owner => user } | ||
| 6 | + before { project.add_access(user, :read) } | ||
| 7 | + | ||
| 8 | + describe "GET /projects" do | ||
| 9 | + it "should return authentication error" do | ||
| 10 | + get "/api/projects" | ||
| 11 | + response.status.should == 401 | ||
| 12 | + end | ||
| 13 | + | ||
| 14 | + describe "authenticated GET /projects" do | ||
| 15 | + it "should return an array of projects" do | ||
| 16 | + get "/api/projects?private_token=#{user.private_token}" | ||
| 17 | + response.status.should == 200 | ||
| 18 | + json = JSON.parse(response.body) | ||
| 19 | + json.should be_an Array | ||
| 20 | + json.first['name'].should == project.name | ||
| 21 | + json.first['owner']['email'].should == user.email | ||
| 22 | + end | ||
| 23 | + end | ||
| 24 | + end | ||
| 25 | + | ||
| 26 | + describe "GET /projects/:id" do | ||
| 27 | + it "should return a project by id" do | ||
| 28 | + get "/api/projects/#{project.code}?private_token=#{user.private_token}" | ||
| 29 | + response.status.should == 200 | ||
| 30 | + json = JSON.parse(response.body) | ||
| 31 | + json['name'].should == project.name | ||
| 32 | + json['owner']['email'].should == user.email | ||
| 33 | + end | ||
| 34 | + end | ||
| 35 | + | ||
| 36 | + describe "GET /projects/:id/repository/branches" do | ||
| 37 | + it "should return an array of project branches" do | ||
| 38 | + get "/api/projects/#{project.code}/repository/branches?private_token=#{user.private_token}" | ||
| 39 | + response.status.should == 200 | ||
| 40 | + json = JSON.parse(response.body) | ||
| 41 | + json.should be_an Array | ||
| 42 | + json.first['name'].should == project.repo.heads.sort_by(&:name).first.name | ||
| 43 | + end | ||
| 44 | + end | ||
| 45 | + | ||
| 46 | + describe "GET /projects/:id/repository/tags" do | ||
| 47 | + it "should return an array of project tags" do | ||
| 48 | + get "/api/projects/#{project.code}/repository/tags?private_token=#{user.private_token}" | ||
| 49 | + response.status.should == 200 | ||
| 50 | + json = JSON.parse(response.body) | ||
| 51 | + json.should be_an Array | ||
| 52 | + json.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name | ||
| 53 | + end | ||
| 54 | + end | ||
| 55 | +end |
| @@ -0,0 +1,38 @@ | @@ -0,0 +1,38 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe Gitlab::API do | ||
| 4 | + let(:user) { Factory :user } | ||
| 5 | + | ||
| 6 | + describe "GET /users" do | ||
| 7 | + it "should return authentication error" do | ||
| 8 | + get "/api/users" | ||
| 9 | + response.status.should == 401 | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + describe "authenticated GET /users" do | ||
| 13 | + it "should return an array of users" do | ||
| 14 | + get "/api/users?private_token=#{user.private_token}" | ||
| 15 | + response.status.should == 200 | ||
| 16 | + json = JSON.parse(response.body) | ||
| 17 | + json.should be_an Array | ||
| 18 | + json.first['email'].should == user.email | ||
| 19 | + end | ||
| 20 | + end | ||
| 21 | + end | ||
| 22 | + | ||
| 23 | + describe "GET /users/:id" do | ||
| 24 | + it "should return a user by id" do | ||
| 25 | + get "/api/users/#{user.id}?private_token=#{user.private_token}" | ||
| 26 | + response.status.should == 200 | ||
| 27 | + JSON.parse(response.body)['email'].should == user.email | ||
| 28 | + end | ||
| 29 | + end | ||
| 30 | + | ||
| 31 | + describe "GET /user" do | ||
| 32 | + it "should return current user" do | ||
| 33 | + get "/api/user?private_token=#{user.private_token}" | ||
| 34 | + response.status.should == 200 | ||
| 35 | + JSON.parse(response.body)['email'].should == user.email | ||
| 36 | + end | ||
| 37 | + end | ||
| 38 | +end |
spec/spec_helper.rb
| @@ -58,4 +58,8 @@ RSpec.configure do |config| | @@ -58,4 +58,8 @@ RSpec.configure do |config| | ||
| 58 | config.after do | 58 | config.after do |
| 59 | DatabaseCleaner.clean | 59 | DatabaseCleaner.clean |
| 60 | end | 60 | end |
| 61 | + | ||
| 62 | + config.include RSpec::Rails::RequestExampleGroup, :type => :request, :example_group => { | ||
| 63 | + :file_path => /spec\/api/ | ||
| 64 | + } | ||
| 61 | end | 65 | end |